Playbook Recipes
Ready-made playbook configurations for SIM swap, takeover, credential leak and port-out, with what each action actually changes.
Overview
Each recipe below is a trigger plus a list of actions to enter by hand in the Playbook Builder wizard. They are not seeded templates: the platform template library has no rows today, so the gallery in step 1 is empty and every playbook starts from scratch.
Building one. Dashboard > Playbooks > New playbook > Start from scratch, name it, pick or type the trigger event type, add the actions, then Activate Playbook. Order in the list is display only: all actions start together, each with its own 8-second budget.
What the actions change. Every action except webhook_callback operates on PasskeyBridge objects that belong to your whole organization: agent delegates, A2A negotiations, cached trust proofs, shadow identities, cross-references and BLAST tunnel sessions. None of them can act on one end user, freeze one account, end one person's session or disable one registered passkey, and none of them filters by the identifier in the signal. webhook_callback is the action that reaches your own systems, and your backend is where per-user work belongs.
What happens without any playbook. A hard signal that carries phone or phone_hash revokes every active agent delegate and every live A2A negotiation on the organization before any action runs. The recipes add to that; they do not cause it.
Recipe 1: SIM-swap response
Trigger: sim_swap (hard signal). Use sim_swap_detected as well if your carrier feed sends the confirmed variant; a playbook matches one exact type, so that is a second playbook.
Scenario: a carrier reports the SIM behind a number has changed, the usual precursor to account takeover on phone-based recovery.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | The only action that reaches your systems: your backend locks the account, drops sessions and disables SMS recovery |
| 2 | suspend_agents | Deactivates the organization's active agent delegates and clears their scopes | Adds scope clearing on top of the automatic revocation |
| 3 | freeze_credentials | Invalidates the organization's valid cached trust proofs | Forces fresh attestation instead of an offline proof issued before the swap |
| 4 | revoke_tokens | Tears down open BLAST tunnel sessions | Any tunnel opened before the swap has to be renegotiated |
| 5 | email_alert | Emails the tenant admins group | Puts a human on it; the affected end user cannot be a recipient |
| 6 | slack_webhook | Posts to the registered Slack destination | Same alert in the channel the on-call watches |
| 7 | log_event | Records severity critical on the event | A marker in the action list for later filtering |
Automatic, without any action: delegates revoked with narrowing_reason: "Hard signal: sim_swap", A2A negotiations set to revoked / auto_revoked with scopes and transaction limits zeroed, and an audit row with action parametric_revocation.triggered.
Recovery: re-delegate agents and re-establish negotiations once the number is confirmed back under the user's control. Restoring a delegate's original scopes is a dashboard action on the Agents tab rather than a playbook one.
Recipe 2: Account takeover containment
Trigger: account_takeover (hard signal).
Scenario: your own detection, or a provider's, concludes an account is in someone else's hands.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend performs the account-level lockdown |
| 2 | quarantine | Revokes cross-references, invalidates cached proofs and deactivates shadow identities in one action | The widest single action: three subsystems at once |
| 3 | revoke_sessions | Revokes active, negotiated and attested A2A negotiations | Marks them session_revoked rather than auto_revoked, so the reason is legible later |
| 4 | email_alert | Emails the tenant admins group | Escalation to a human |
| 5 | slack_webhook | Posts to the registered Slack destination | Channel visibility |
| 6 | log_event | Records severity critical | Audit marker |
Difference from recipe 1: quarantine also revokes cross-reference bindings, which SIM-swap response leaves alone. It is not a softer option; both leave the delegates deactivated by the automatic hard-signal revocation.
Automatic: identical to recipe 1, because account_takeover is classified hard.
Recipe 3: Credential leak containment
Trigger: credential_leak (soft signal).
Scenario: credentials tied to the identifier you hash have turned up in breach data.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend forces the password reset and notifies the person; PasskeyBridge cannot email your end user |
| 2 | step_up_auth | Deactivates the organization's active shadow identities | The next request through a shadow identity has to re-authenticate |
| 3 | email_alert | Emails the tenant admins group | Tells your security team, who are the only people this action can reach |
| 4 | log_event | Records severity warning | Audit marker |
Automatic: no revocation. A soft signal dispatches one evaluate_tenant trust evaluation for the organization, debounced to one per signal type per 30 seconds, and the event records graduated_trust_evaluation.
Sending the password hash. Add credential_sha1, the uppercase SHA-1 of the password, to the ingest body and the pipeline runs a k-anonymity check against Have I Been Pwned and returns hibp_compromised and hibp_breach_count in the response. The plaintext never leaves your side.
Recipe 4: SS7 intercept response
Trigger: ss7_intercept (hard signal).
Scenario: signalling-layer interception of SMS or voice for a number you rely on.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend disables SMS-based verification for that number |
| 2 | suspend_agents | Deactivates the organization's delegates and clears their scopes | Scope clearing on top of the automatic revocation |
| 3 | freeze_credentials | Invalidates valid cached trust proofs | No offline proof survives the interception window |
| 4 | revoke_tokens | Tears down open BLAST tunnel sessions | Forces a fresh handshake |
| 5 | email_alert | Emails the tenant admins group | SS7 interception warrants a human |
| 6 | log_event | Records severity critical | Audit marker |
Automatic: delegates and A2A negotiations revoked, as for every hard signal.
After it fires: the phone number is the compromised channel, so treat any SMS or voice verification on it as unavailable until the carrier confirms otherwise. Passkey authentication is unaffected by SS7.
Recipe 5: Device change monitoring
Trigger: device_change (soft signal). unusual_device is a second soft type and needs its own playbook.
Scenario: a new device appears on an account: a genuine upgrade, or an attacker after a credential theft.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend decides whether to challenge the session and whether to ask the user |
| 2 | step_up_auth | Deactivates the organization's active shadow identities | Re-authentication on the next request through one |
| 3 | log_event | Records severity info | A device-change trail on the event rows |
Automatic: one debounced trust evaluation, no revocation.
Keep this one small. step_up_auth acts on every shadow identity the organization holds, not only the one behind this signal, so on a busy organization a frequent trigger makes it a blunt instrument. A playbook of webhook_callback plus log_event and a decision in your own backend is often the better shape for a routine soft signal.
Recipe 6: Velocity anomaly alert
Trigger: velocity_anomaly (soft signal).
Scenario: authentication attempts arriving faster, or from further apart, than a person could manage.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | slack_webhook | Posts to the registered Slack destination | Immediate visibility while the burst is live |
| 2 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend raises monitoring or challenges the session |
| 3 | log_event | Records severity warning | Audit marker |
Automatic: one debounced trust evaluation, no revocation.
The trust engine watches velocity separately. Its velocity signal is computed from agent activity rows recorded through shield-agent-trust, more than 50 actions by one delegate in a 5-minute window, weighted up to 0.30 against the trust score. That is a different input from this signal, so a velocity anomaly in your application does not by itself move any delegate's score.
Alert on the rate instead of the event. For volume rather than individual signals, add an alert rule in the Observability tab on the events_per_hour metric with an operator, a threshold and a channel. Rules are evaluated every 5 minutes.
Recipe 7: Fraud ring detection
Trigger: credential_stuffing_attempt (soft signal).
Scenario: one campaign working through many accounts at once.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend correlates across accounts and rate-limits the source |
| 2 | quarantine | Revokes cross-references, invalidates cached proofs and deactivates shadow identities | Organization-wide, so reserve it for a campaign you are prepared to interrupt for everyone |
| 3 | email_alert | Emails the tenant admins group | Cross-account investigation is human work |
| 4 | slack_webhook | Posts to the registered Slack destination | Channel visibility |
| 5 | log_event | Records severity warning | Audit marker |
Automatic: one debounced trust evaluation, no revocation.
Correlating across accounts. The clustering engine groups recent events for the organization by type, hashed-identifier prefix, time band and risk bucket, and surfaces them in Dashboard > Intelligence > Clusters on the Enterprise plan. The cross-reference API stores and lists bindings between SIM attestations and credentials for the organization; it has no lookup-by-hash action, so it answers "what is bound" rather than "who else shares this".
Consider the blast radius. If interrupting every agent and proof on the organization is too much for a stuffing campaign, drop action 2 and let the webhook drive a per-account response in your own system.
Recipe 8: Number port-out response
Trigger: port_out (hard signal). number_port and number_porting are separate hard types with the same treatment, and each needs its own playbook to match.
Scenario: the number has moved to another carrier.
| Order | Action | What it changes | Why it is here |
|---|---|---|---|
| 1 | webhook_callback | POSTs the signed envelope to your callback URL | Your backend disables phone-based verification and locks the account |
| 2 | suspend_agents | Deactivates the organization's delegates and clears their scopes | Scope clearing on top of the automatic revocation |
| 3 | freeze_credentials | Invalidates valid cached trust proofs | Proofs issued before the port should not keep verifying |
| 4 | email_alert | Emails the tenant admins group | Human review of a confirmed control change |
| 5 | log_event | Records severity critical | Audit marker |
Automatic: delegates and A2A negotiations revoked, as for every hard signal.
Combining recipes and action limits
One playbook per signal. The oldest active playbook whose trigger matches is the one that runs, and no other playbook sees that signal. Two playbooks on sim_swap means the second is dead weight; combine the actions into the older row.
Order is display only. Actions all start together under Promise.all, each with its own 8-second budget, so there is no way to make an enforcement action complete before a notification goes out. If the sequence matters, drive it from your own backend off webhook_callback.
One of each type. The wizard refuses to add a type that is already present, so a playbook cannot hold two webhooks to different URLs. A second destination needs a second trigger type, or a fan-out in your own receiver.
Plan limits are not enforced. Starter's one playbook and Pro's ten are commercial terms; no function counts playbooks, and nothing refuses the next one.
Testing a playbook. Dashboard > Overview > Send test signal posts event_type: "test_signal" with x-pb-test-mode: true and metadata.source: "dashboard_simulator". Replay an attack in test mode sends six credential_stuffing_attempt signals, a failed_verification and a suspicious_login as test events and reports which of your playbooks matched, once per ten minutes. Both are real trips through the pipeline: the event rows are written with test_mode = true, nothing is metered, and only email_alert, slack_webhook and webhook_callback are suppressed (recorded as skipped_test_mode).
The exemption is the header or the key, never the event type. A signal with event_type: "test_signal" sent from your own backend with a live pb_live_ key is ordinary billed traffic: its playbook runs and its outbound actions really fire. What suppresses sends is x-pb-test-mode: true with a tenant-admin session, or a pb_test_ sandbox key. Neither of those suppresses hard-signal revocation, so never replay a hard signal against a production organization to "see what happens".
Hard signal reference.
| Signal type | Class | Revoked inline by the ingest pipeline |
|---|---|---|
sim_swap | Hard | Agent delegates and A2A negotiations |
sim_swap_detected | Hard | Agent delegates and A2A negotiations |
port_out | Hard | Agent delegates and A2A negotiations |
number_port | Hard | Agent delegates and A2A negotiations |
number_porting | Hard | Agent delegates and A2A negotiations |
device_compromise | Hard | Agent delegates and A2A negotiations |
ss7_intercept | Hard | Agent delegates and A2A negotiations |
account_takeover | Hard | Agent delegates and A2A negotiations |
scope_poisoning | Hard | Agent delegates and A2A negotiations |
Related from the blog
- Feeding a Hard Deny into Your Fraud Rules Engine: Integration Patternsengineering · 10 min read
- You Detect SIM Swaps. But What Happens in the Next 50 Milliseconds?security · 8 min read
- Account Recovery Is the Front Door: Carrier-State Checks in Credit Union and Community Bank Recovery Flowssecurity · 11 min read