← All field notes
gcpcloud schedulerfor responders

Cloud Scheduler persistence: a saved cron that outlives every session

A rogue Cloud Scheduler job fires attacker code on a cron as a service account. It survives reboots and key rotations because it is a saved schedule. Here is how you remove it.

Cloud Scheduler runs code on a cron as an attached service account, which makes a rogue job ideal quiet persistence. It survives reboots and key rotations because it is a saved schedule, not a session.

How the attack works

An attacker with project-level access creates a Cloud Scheduler job that fires on a recurring cron and invokes an attacker-controlled target, an HTTP endpoint, a Pub/Sub publish, or a Cloud Function, with an attached invoker service account via OIDC. Cloud Audit Logs record a cloudscheduler.jobs.create from a principal outside the IaC pipeline that is not reflected in the declared jobs. The job fires, the target runs with the invoker service account’s identity, and it fires again on the next interval to prove durable, automated re-entry. In ATT&CK terms this is T1053, Scheduled Task or Job, with T1648, Serverless Execution, and T1098, Account Manipulation.

Why it works

The attacker could create scheduler jobs and attach a privileged invoker service account through iam.serviceAccounts.actAs. Because the persistence is a stored schedule, it re-fires independent of any live session, surviving reboots and credential rotations.

How to fix it

Killing one execution or blocking the target URL leaves the saved job to fire again or be repointed. Pause and delete the scheduler job, then scope or rotate the invoker service account so a re-created job cannot run with its rights. Going forward, reconcile all jobs to the IaC inventory, restrict job creation and actAs, least-privilege every invoker, and alert on cloudscheduler.jobs.create. Scope what ran from Cloud Audit Logs filtered to the invoker across every run, since persistence makes dwell time part of the impact.

Practice it

We built this as a GraphLattice Range scenario so responders can rehearse the saved-schedule persistence, the delete-and-scope containment, and the actAs governance fix.