This check flags GCP IAM audit logging configs that exempt specific members from being logged, which creates blind spots an attacker or insider can hide behind. Fix it by removing the exemptedMembers entries from your project, folder, or organization audit config.
Audit logs are the record of who did what in your GCP environment. When you exempt a member from audit logging, you are deciding that this particular identity's actions do not need to be recorded. That sounds harmless until you consider what those records are actually for: investigating an incident, satisfying a compliance auditor, or proving a service account was not the one that deleted a production bucket.
The Members Exempted From Audit Logging check (iam_auditexemptions) inspects your IAM audit configuration and reports any principals listed under exemptedMembers. If the list is not empty, you have at least one identity whose activity is silently excluded from Cloud Audit Logs.
What this check detects
In GCP, audit logging is configured through an auditConfigs block that lives on a project, folder, or organization IAM policy. Each entry specifies a service (for example allServices or storage.googleapis.com) and one or more log types: ADMIN_READ, DATA_READ, and DATA_WRITE.
Within each log type, you can add an exemptedMembers array. Any principal in that array will not generate audit log entries for that log type and service. A configuration that looks like this is exactly what the check catches:
{
"auditConfigs": [
{
"service": "allServices",
"auditLogConfigs": [
{ "logType": "ADMIN_READ" },
{
"logType": "DATA_WRITE",
"exemptedMembers": [
"serviceAccount:[email protected]"
]
}
]
}
]
}
Here the ETL service account's data-write activity across all services is invisible. If that account is compromised, or if it does something it should not, there is no trail.
Note: Exemptions are sometimes added deliberately to cut down on log volume from chatty service accounts. The intent is usually cost control, not malice. But the security trade-off is rarely revisited once the exemption is in place.
Why it matters
Audit logs only have value if they are complete. An exemption punches a hole in that completeness, and the hole tends to land on exactly the identities that matter most: highly privileged service accounts that move data around.
Incident response goes blind
Imagine a service account key leaks. The attacker uses it to exfiltrate data from Cloud Storage. During the investigation you pull the audit logs to scope the blast radius, and the DATA_WRITE and DATA_READ events for that account simply are not there. You cannot tell which buckets were touched, when, or how much data moved. The exemption that was added to save a few dollars a month has now turned a contained incident into an open question you cannot answer.
Insider abuse becomes deniable
An exempted human or service principal can take actions that leave no record. That is the textbook setup for insider threat. Someone with both the exemption and the access can modify or remove resources without producing the evidence you would normally rely on to hold them accountable.
Warning: Attackers who gain enough IAM privilege will sometimes add themselves to exemptedMembers as an anti-forensic step. If you find an exemption you do not recognize, treat it as a potential indicator of compromise, not just a misconfiguration.
Compliance failures
Frameworks like PCI DSS, SOC 2, HIPAA, and the CIS Google Cloud Foundations Benchmark require complete and tamper-evident audit trails. CIS benchmark control 2.1 specifically expects audit logging to be configured with no exempted members. An exemption is a direct finding against these standards and can stall an audit.
How to fix it
The remediation is to remove the offending principals from exemptedMembers. You can do this through the console, the gcloud CLI, or your infrastructure-as-code tooling.
Step 1: Find where the exemption lives
Export the current IAM policy and look at the auditConfigs block. Check the project, but also the parent folder and organization, since audit config is inherited downward.
gcloud projects get-iam-policy my-project \
--format=json > policy.json
# inspect the auditConfigs block
cat policy.json | jq '.auditConfigs'
Step 2: Remove the exempted members
Edit policy.json and delete the exemptedMembers arrays (or the specific principals) you want to stop exempting. The corrected block should look like this:
{
"auditConfigs": [
{
"service": "allServices",
"auditLogConfigs": [
{ "logType": "ADMIN_READ" },
{ "logType": "DATA_WRITE" },
{ "logType": "DATA_READ" }
]
}
]
}
Danger: set-iam-policy overwrites the entire IAM policy, not just the audit config. Always edit the exact policy you exported with get-iam-policy and apply it back with its etag intact. Applying a stale or hand-built policy can wipe role bindings and lock people out.
Step 3: Apply the corrected policy
gcloud projects set-iam-policy my-project policy.json
The etag field in the exported policy guards against race conditions. If someone changed the policy between your export and your apply, the command fails rather than clobbering their change. Re-export and retry if that happens.
Fixing it in Terraform
If your audit config is managed with Terraform, the fix is to remove the exempted_members argument from the relevant audit_log_config block:
resource "google_project_iam_audit_config" "all_services" {
project = "my-project"
service = "allServices"
audit_log_config {
log_type = "ADMIN_READ"
}
audit_log_config {
log_type = "DATA_WRITE"
# exempted_members removed - was exempting the ETL service account
}
audit_log_config {
log_type = "DATA_READ"
}
}
terraform plan
terraform apply
Warning: Removing exemptions will increase your log volume, and DATA_READ and DATA_WRITE logs are billable above the free allotment. Estimate the additional volume first, especially for high-throughput service accounts, so the change does not surprise you on the next bill.
How to prevent it from happening again
Removing one exemption is a point fix. Stopping the next one requires guardrails in the places where config gets changed.
Block it in CI/CD with policy-as-code
If you provision IAM through Terraform, gate merges on a policy check that fails whenever exempted_members appears. With Open Policy Agent and Conftest you can write a rule like this:
package main
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_project_iam_audit_config"
config := resource.change.after.audit_log_config[_]
count(config.exempted_members) > 0
msg := sprintf(
"Audit config for service %q has exempted members: %v",
[resource.change.after.service, config.exempted_members]
)
}
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy ./policies
Enforce with an Organization Policy
While there is no single org policy constraint that bans exemptions outright, you can require audit logging defaults across the org and detect drift centrally. Set a baseline audit config at the organization level so projects inherit complete logging, then alert on any project-level override.
Tip: Create a log-based alert that fires on the SetIamPolicy admin activity event when the request payload contains exemptedMembers. That way you hear about a new exemption within minutes instead of finding it during your next audit. Lensix surfaces this finding continuously so you do not have to build the detection yourself.
Continuous scanning
Configuration drifts. Someone runs a one-off gcloud command during an incident, a new project is created outside Terraform, or an old exemption gets copied into a new service definition. Continuous posture scanning catches these between deployments rather than only at merge time.
Best practices
- Treat exemptions as exceptions, not defaults. The base posture should be zero exempted members. If a team needs one, it should go through a review with a documented justification and an expiry date.
- Solve log volume the right way. If a service account is producing too many logs, exclude or route those logs at the sink level with a filter rather than exempting the account from audit logging entirely. You still keep the data trail and can ingest it into cheaper storage.
- Manage audit config in code. Click-ops exemptions are invisible until they cause a problem. Keeping
auditConfigsin Terraform makes every change reviewable and revertible. - Enable all three log types where it counts.
ADMIN_READis on by default and free, butDATA_READandDATA_WRITEare what tell you about data access. Enable them on sensitive services even if not everywhere. - Audit your audit config. Quarterly, review every
exemptedMembersentry across projects, folders, and the org. Remove anything that is no longer justified. - Protect the logs themselves. Complete logs are only useful if they cannot be altered. Lock down who can call
SetIamPolicyand who can modify log sinks and retention.
Note: Admin Activity logs cannot be disabled or exempted in the same way, which is why exemptions mostly affect Data Access logs. That is also why this finding tends to hide the data-level actions, reads and writes, that matter most during an exfiltration investigation.
An exemption is a small line in a config file with an outsized effect on your ability to investigate, prove, and comply. Remove the ones you have, gate the ones you might add, and keep the audit trail whole.

