> For the complete documentation index, see [llms.txt](https://docs.forestall.io/fsprotect/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/fsprotect/edges/gcp/gcp_can_unlink_billing.md).

# GCP\_CAN\_UNLINK\_BILLING

## Summary

|                            |                                                       |
| -------------------------- | ----------------------------------------------------- |
| **FSProtect ACL Alias**    | GCP\_CAN\_UNLINK\_BILLING                             |
| **GCP Alias**              | Guardrail Bypass & Destruction                        |
| **Affected Object Types**  | Projects                                              |
| **Exploitation Certainty** | Certain                                               |
| **Granting Roles**         | `roles/billing.admin`, `roles/billing.projectManager` |

## Description

`GCP_CAN_UNLINK_BILLING` indicates that an identity can remove the **billing account** association from a GCP project. When a billing account is unlinked, all billable GCP services in the project are immediately disabled — compute instances stop, Cloud Run services become unavailable, GKE control planes are disabled, and billable API calls fail. The project's resources are not deleted, but they are inaccessible until billing is re-linked.

This edge represents an **availability attack** surface. An attacker who cannot exfiltrate or destroy data (due to VPC-SC or encryption) can still cause a service outage by unlinking billing. In organizations with strict billing separation, an identity with `roles/billing.admin` at the billing account level may be able to unlink billing from any project associated with that account.

**Key abuse scenarios:**

* Unlink billing from production projects → all compute and managed services stop immediately.
* Unlink billing from security or logging projects → blind defenders before a larger attack.
* Cloud extortion: unlink billing from business-critical projects and demand payment before data is lost to resource deletion (note: resources are not deleted immediately, but the pressure is real).

## Identification

### gcloud CLI

```bash
# Find who has billing admin or project billing manager at org or billing account level
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud organizations get-iam-policy $ORG_ID --format=json | \
  jq '.bindings[] | select(.role | test("billing.admin|billing.projectManager")) | {role: .role, members: .members}'

# Check the billing account linked to a specific project
PROJECT_ID="my-project"
gcloud billing projects describe $PROJECT_ID \
  --format="table(billingAccountName, billingEnabled)"

# List all projects linked to a billing account
BILLING_ACCOUNT=$(gcloud billing accounts list --format="value(name)" | head -1)
gcloud billing projects list --billing-account=$BILLING_ACCOUNT \
  --format="table(projectId, billingEnabled)"
```

### GCP Console

1. Open **GCP Console** → **Billing** → select the billing account.
2. Click **Account management** → review all linked projects.
3. Check **IAM & Admin** → **IAM** at the billing account level for principals with `Billing Account Administrator` or `Project Billing Manager`.

## Exploitation

### gcloud CLI

```bash
# Unlink billing from a single project — all billable services stop immediately
PROJECT_ID="target-project"
gcloud billing projects unlink $PROJECT_ID

# Mass unlink: remove billing from all projects the identity has rights on
for PROJECT in $(gcloud projects list --format="value(projectId)"); do
  echo "Unlinking billing from: $PROJECT"
  gcloud billing projects unlink $PROJECT
done
```

Services that stop immediately after billing is unlinked:

* Compute Engine VMs (instances stop running)
* Cloud Run services (requests begin failing)
* GKE clusters (control plane is disabled)
* Cloud SQL instances (connections are refused)
* BigQuery (queries fail with quota errors)

Free-tier and always-free resources continue operating within their limits.

## Mitigation

1. **Restrict `roles/billing.admin`** — assign to at most a dedicated finance or ops account; never to developer identities.
2. **Restrict `roles/billing.projectManagerr`** to approved automation accounts with narrow scope.
3. **Enable budget alerts** — a sudden drop to zero spend can indicate billing was unlinked before the operational impact is noticed.
4. **Maintain runbooks** for re-linking billing under incident conditions, including the identity and approvals required.

## Detection

| Log Type       | Method                     | Key Fields                                                 |
| -------------- | -------------------------- | ---------------------------------------------------------- |
| Admin Activity | `UpdateProjectBillingInfo` | `resource.type=project`, `billingAccountName` set to empty |

```bash
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud logging read \
  'protoPayload.methodName="UpdateProjectBillingInfo"' \
  --organization=$ORG_ID \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, resource.labels.project_id, protoPayload.request.projectBillingInfo.billingAccountName)"
```

Alert on:

* Any `UpdateProjectBillingInfo` call where `billingAccountName` is set to an empty value (unlinking).
* Multiple billing unlinks within a short time window (mass disruption pattern).
* Billing changes outside of business hours or from identities not in the approved billing admin list.

## References

* <https://cloud.google.com/billing/docs/how-to/modify-project>
* <https://cloud.google.com/billing/docs/concepts>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestall.io/fsprotect/edges/gcp/gcp_can_unlink_billing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
