TILLSHIELD · PLAYBOOKS

From a finding to a response, with a person in the loop.

GA

A playbook is what TillShield does about a TillTell finding: tell the right people, make an account prove its second factor, sign it out, block an address at the edge, stop an app session from sending data, or end a process on a host and cut the host off the network. Every live rule names the playbook it suggests. When it fires, the run is proposed, the security recipients hear about it, and an owner or admin decides. Automation is earned one rule at a time, and every action lands in the workspace audit log.

01Actions

Seven things a playbook can do

Each action has a blast radius. Low-blast actions are reversible and take no access away; high-blast actions sign someone out, turn traffic away or act on a host, and wait for a person unless the rule has earned unattended runs.

ActionBlastWhat it does
notifylowSends the finding, its record and a link to the security recipients by email, Slack and signed webhook.
challenge_mfalowEnds the actor’s sessions so their next sign-in has to pass the second factor they enrolled. Fails when they have none.
revoke_sessionshighSigns the actor out everywhere. They can sign in again; whoever holds a stolen session cannot.
block_iphighBlocks the source address at the inline WAF for a fixed time, 24 hours by default, then lifts it.
quarantine_sessionhighDrops telemetry from the reporting app session for 24 hours. The user is not signed out.
kill_processhighEnds the process the finding names, on the host that reported it. The endpoint agent first checks the PID still runs the same binary.
isolate_hosthighCuts the host that reported the finding off the network, except its link to TillShield, until someone releases it or for a set time.

The library

PlaybookStepsReminder · expiry
notify-security-ownersnotify30 min · 24 h
challenge-mfa-and-notifychallenge_mfa, notify; sign out everywhere if the challenge cannot be forced15 min · 12 h
revoke-sessions-and-notifyrevoke_sessions, notify15 min · 12 h
block-ip-at-edgeblock_ip for 24 hours, notify10 min · 6 h
quarantine-sessionquarantine_session, notify30 min · 24 h
kill-process-and-notifykill_process, notify10 min · 1 h
isolate-host-and-notifyisolate_host until released, notify10 min · 6 h

Shield → Playbooks → Library shows each one with its steps, the rules that suggest it and its YAML; tilldev shield playbooks show prints the same.

02The approval ladder

Who has to say yes

Only a live rule proposes its playbook. Advisory findings alert and suggest nothing; shadow findings stay on the TillTell page. What runs without a person depends on where the workspace and the rule stand:

PhaseWhenWhat runs on its own
AThe default.Nothing. Every step waits for an owner or admin.
B“Run low-blast steps on their own” is on in Shield → Settings.Notifications and second-factor challenges. Sign-outs, blocks, quarantines and host actions still wait.
CThe rule earned unattended runs, the TillTell switch is on, and an owner or admin confirmed automation for that rule.Every step.

A playbook whose approval mode is human_required never runs a step without a person, whatever the phase. An owner or admin can also start any playbook on a finding by hand from the TillTell page; starting it is the approval for every step.

Deciding

Owners and admins see waiting runs in the notification bell and under Shield → Playbooks, and the alert links straight to the run. Approve or turn down all the waiting steps or only some, with a note. A step that depends on another (sign out if the challenge failed) runs or is skipped once the first one finishes.

Nobody turns down their own sign-out
When a run acts on a workspace member, that member cannot turn it down, even as an owner. Someone with a stolen owner session could otherwise dismiss the response to their own break-in. Another owner or admin decides, or the run expires.

Deadlines

A waiting run reminds the recipients once at the playbook’s reminder time, then expires: the waiting steps are skipped, the run is marked expired, and nothing more happens. Steps that already ran stay done. An approval and an expiry that land together never both win; whichever is recorded first holds.

03Accounts

Who an account action may touch

challenge_mfa and revoke_sessions act on a person, so they demand evidence a Till service recorded itself. On evidence an app SDK only reported, they are withheld and the step says why, unless the workspace turned on Allow client-triggered revocation in Shield → Settings.

  • Workspace members named by workspace, TillForge, TillSecrets or TillArk findings. A finding about a token or a service is refused: revoke that credential instead.
  • TillAuth users of this workspace’s apps, named by TillAuth findings, or by app findings whose user id is the SHA-256 of the TillAuth user id.
Signed outHow fast it takes hold
Workspace memberEvery session ends at once, and pages already open stop working within about 30 seconds. If that cut-off cannot be recorded, the step says so, and open pages last until their access token expires. API keys and agent tokens are not touched.
TillAuth userEvery session ends at once. An access token already issued keeps working until it expires, at most 10 minutes.

A challenge needs a second factor to challenge: an authenticator app for workspace members, an authenticator app or a push device for TillAuth users. Without one, the step fails and says so.

04Edge blocks

Blocking an address

A block is an ordinary inline WAF rule with an expiry, placed on the address in the finding’s record. It lifts on its own; a second block on the same address extends it rather than stacking. Blocks appear under Shield → Inline WAF, marked with the run that placed them.

  • An edge key has to be in use. If no TillShield edge key in the workspace has fetched rules, a block would be enforced nowhere, so the step fails and says so.
  • Private and reserved addresses are refused, so a playbook cannot cut off your own infrastructure.
  • Hashed addresses. TillGate keeps visitor addresses as hashes, and a block on one matches the hash. It is enforced by @tillstack/shield-core and @tillstack/shield-cloudflare 0.3.2 or later; older versions skip the rule rather than guess.
Shared addresses
Mobile carriers and many offices put thousands of people behind one public address. A block on it turns all of them away for as long as it lasts. That is why block_ip is high-blast and waits for a person by default.
05Hosts

Ending a process and isolating a host

kill_process and isolate_host act through the TillTell endpoint agent. The step sends the host a command signed by TillShield and waits for the agent to say what happened; the run carries on once it does. An online agent picks a command up within about a minute.

  • Only the host that reported it. The step acts on the host the server knows sent the event, never on a host an event names. A finding from any other source fails the step and says so.
  • The host must be approved, and host commands must be set up on the server. A pending or revoked host fails the step.
  • A process is ended only if it is still the same one. The event has to name the binary as well as the PID, and the agent checks the PID still runs that binary, so a reused PID is never hit.
  • An isolated host stays reachable by TillShield, so it keeps reporting and can be released from Shield → Endpoints. allow keeps up to 16 more networks open, and for lifts the isolation by itself after 5 minutes to 30 days. A playbook doesn’t isolate a host while a release someone asked for is on its way, and a host that is already isolated counts as done.
  • Lapses fail the step. A host that never takes the command before it lapses, after 15 minutes for a kill and a day for an isolation, fails the step, and nothing ran. Calling the command back under Shield → Endpoints fails it too.
yaml
steps:
  - id: isolate
    action: isolate_host
    params:
      allow: [10.0.8.0/24]   # also reachable while isolated
      for: 4h                # lifts by itself; leave out to isolate until released
  - id: notify
    action: notify
06Security alerts

Email, Slack and a signed webhook

Shield → Settings → Playbooks & security alerts sets who hears about findings and runs. Email goes to the addresses listed there, or to the workspace’s owners and admins when the list is empty. Slack takes an incoming-webhook URL. The webhook takes any public https endpoint. A finding alert for one rule and the same subject goes out at most once every 15 minutes; a run waiting for approval always says so. Findings from labelled drills never alert. TillDrill sends its own alerts here too, when a scheduled run finds checks newly failing or any run finds that a target’s proof has lapsed.

Webhook typeSent when
tilltell.findingAn advisory or live rule fires and no run announces it.
tillshield.playbook.notifyA run’s notify step runs.
tillshield.playbook.approval_neededA run is waiting for a person.
tillshield.playbook.escalatedNobody decided by the reminder time.
tillshield.playbook.failedA run ended with a failed step.
tillshield.drill.checks_failingA scheduled TillDrill run finds checks newly failing at medium or above.
tillshield.drill.target_lapsedA TillDrill run finds that a verified target’s proof no longer holds.
tillshield.posture.failingA Posture sync finds checks in alert mode newly failing.
tillshield.vulns.overdueItems in the vulnerability inventory pass their due date; each one is named once.
tillshield.disclosure.receivedResearchers confirm new reports to your disclosure program.
tillshield.disclosure.replyResearchers reply on their reports.
tillshield.engagement.stateAn engagement starts, pauses, ends testing, closes or is cancelled.
tillshield.engagement.findingsTesters report new findings on an engagement.
json
{
  "type": "tillshield.playbook.approval_needed",
  "delivery_id": "5b0d3c3e-…",
  "finding": {
    "id": "9f1c…", "rule_id": "tell-account-brute-force",
    "title": "Brute force on one account", "level": "high", "stage": "live",
    "source": "tillauth", "fired_at": "2026-10-01T09:14:03.000Z", "drill": false,
    "incident_id": "e07a…"
  },
  "run": { "id": "c41e…", "playbook_id": "revoke-sessions-and-notify", "status": "proposed", "awaiting": ["revoke"] },
  "link": "https://tilldev.dev/acme/shield/playbooks?run=c41e…"
}

finding.incident_id is the incident the finding is in, or null. TillDrill alerts carry target, run and failures in place of finding; their shape is on the TillDrill page, and the overdue alert’s on the vulnerabilities page, and the disclosure alerts’ on the disclosure page, and the engagement alerts’ on the engagements page. The first webhook you save gets a signing secret, shown once. Each delivery carries X-TillPulse-Webhook-Signature and X-TillPulse-Delivery, verified exactly as alert-rule webhooks are. Rotate the secret from the settings block or the CLI; the old one stops verifying at once.

07Drills

Drills touch nothing

A finding from a labelled drill gets its playbook planned like any other, but every step is simulated: it records what it would have done (“would sign the actor out everywhere”) and acts on nobody. Drill runs never alert, never wait for approval and sit under their own tab in Shield → Playbooks.

08CLI and API

From the terminal

bash
# the library
tilldev shield playbooks ls
tilldev shield playbooks show revoke-sessions-and-notify

# what is waiting for you, and one run in full
tilldev shield playbooks runs --waiting
tilldev shield playbooks run <run-id>

# decide: all waiting steps, or only some
tilldev shield playbooks approve <run-id>
tilldev shield playbooks reject <run-id> --steps revoke --note "known travel, confirmed by phone"

# respond by hand to a finding
tilldev shield playbooks start <finding-id> block-ip-at-edge

# who hears about it
tilldev shield playbooks settings
printf %s "$SLACK_WEBHOOK_URL" | tilldev shield playbooks settings set --slack-stdin
tilldev shield playbooks settings set --emails secops@example.com,oncall@example.com --auto-low-blast
tilldev shield playbooks settings set --webhook https://hooks.example.com/security
tilldev shield playbooks settings rotate-secret

The same operations are on the HTTP API under /api/shield/playbooks/…, documented in the API reference. Approvals, rejections, runs started by hand, settings changes and every step a playbook takes land in the workspace audit log.