| name | user-graph-traversal |
| description | Traverse a Warp user's terminal ID / user graph to find all accounts that have shared the same computer (anonymous terminal ID). Use when investigating whether a user has multiple accounts, finding connected fraud rings via shared devices, or asked to "traverse the user graph", "find related accounts", "find accounts sharing the same computer", or "find connected users" for a given email or user.
|
User Graph Traversal
When a user creates a Warp account, their computer's anonymous terminal ID is linked
to their user ID. This creates a graph: multiple accounts that have logged into the
same machine share terminal IDs and can be connected via 2-hop traversal.
Schema config
The bq query below uses the default logical mapping: project YOUR_GCP_PROJECT
and tables core_user_facts, int_user_id_to_terminal_anonymous_id_mapping,
core_ai_cycles_clean in the prod dataset. Replace them with your physical names
from config/schema.json (see SCHEMA.md).
Query (seed by email)
bq query --use_legacy_sql=false --format=prettyjson '
with
seed as (
select user_id
from `YOUR_GCP_PROJECT.prod.core_user_facts`
where user_email = "USER_EMAIL_HERE"
)
, seed_anon_ids as (
select distinct terminal_anonymous_id
from `YOUR_GCP_PROJECT.prod.int_user_id_to_terminal_anonymous_id_mapping`
where user_id in (select user_id from seed)
and terminal_anonymous_id != ""
)
, users_hop1 as (
select distinct user_id
from `YOUR_GCP_PROJECT.prod.int_user_id_to_terminal_anonymous_id_mapping`
where terminal_anonymous_id in (select terminal_anonymous_id from seed_anon_ids)
and terminal_anonymous_id != ""
)
, anon_ids_hop2 as (
select distinct terminal_anonymous_id
from `YOUR_GCP_PROJECT.prod.int_user_id_to_terminal_anonymous_id_mapping`
where user_id in (select user_id from users_hop1)
and terminal_anonymous_id not in (select terminal_anonymous_id from seed_anon_ids)
and terminal_anonymous_id != ""
)
, users_hop2 as (
select distinct user_id
from `YOUR_GCP_PROJECT.prod.int_user_id_to_terminal_anonymous_id_mapping`
where terminal_anonymous_id in (select terminal_anonymous_id from anon_ids_hop2)
and terminal_anonymous_id != ""
and user_id not in (select user_id from users_hop1)
)
, connected_users as (
select user_id from users_hop1
union distinct
select user_id from users_hop2
)
, current_cycles as (
select
user_id
, total_credits_used as total_requests_used
, plan_type_at_cycle_end
from `YOUR_GCP_PROJECT.prod.core_ai_cycles_clean`
where is_current_cycle
)
select
cu.user_id as firebase_uid
, cuf.user_email as email
, cuf.signup_timestamp as created_at
, coalesce(cc.total_requests_used, 0) as total_requests_used
, case
when coalesce(cc.plan_type_at_cycle_end, "free") = "free" then "free"
else "active"
end as paid_status
, cuf.reputation_status
from connected_users cu
join `YOUR_GCP_PROJECT.prod.core_user_facts` cuf
using (user_id)
left join current_cycles cc
using (user_id)
order by total_requests_used desc
'
Output
| Column | Description |
|---|
firebase_uid | User ID |
email | Account email |
created_at | Signup timestamp |
total_requests_used | AI requests used in current cycle |
paid_status | free or active (paid) |
reputation_status | e.g. unreputable, reputable, reputable_from_override |
Output Guidance
Filter by reputation status first. Skip any user with reputation_status of reputable or reputable_from_override — these have already been cleared and are not worth investigating. Focus only on users with reputation_status = unreputable or null.
After running the query, report:
Summary stats
- Total connected users, broken down as free vs. active (e.g., "Found 47 connected users: 44 free, 3 active")
- Total AI requests consumed by free accounts in the cluster
Active (paid) users — list each with email and requests used. These are the most suspicious:
- Many free accounts surrounding a paid account may mean the paid account used a stolen credit card to fund credit farming
- Flag: "Users X, Y, Z are 'active' — worth checking for credit card fraud"
Signup timeline — scan the created_at values for bursts:
- Multiple accounts created on the same day = strong fraud signal
- Flag any days with 3+ signups (e.g., "10 accounts signed up on 2025-11-03")
Fraud signal strength — summarize your read:
- 🔴 High: many free accounts, signup bursts, active accounts present
- 🟡 Medium: moderate cluster size, no clear bursts
- 🟢 Low: small cluster, organic signup spread, matches a household/team