The Blind Spot in Warp Terminal’s Network Monitor
Recently, I gave Warp terminal a shot for curiosity. While the AI aspect of it was unappealing to me, it was developed in Rust and boasts fast boot time, and a decent pre-configured development environment.
With privacy concerns, it offers a built-in “network monitor log” described as letting the user view all communications to external servers for transparency. Yet it doesn’t; the output is heavily trimmed, and has a systematic blind spot for critical, user-sensitive data.
The binary is bundled with API keys in plaintext. Network logs include auth tokens and stable identifiers (e.g. Firebase UIDs) that are not anonymized, while the network log hides packets from the user.
A RudderStack identifier (rl_anonymous_id) is issued via cookies during standard API responses, independent of explicit telemetry settings. The value appears to be rotated rather than strictly persistent.
Tooling
All analysis was performed using the tools below.
- Windows 11
- Warp
v0.2026.03.25.08.24.stable_05(sha1:0bf33c5461095cd9b89040c1bc4938f6ff23bb7b) - Ghidra
strings- Cutter
frida(hook script here)- ProcMon
- Wireshark
Every telemetry option disabled (Help improve Warp, Send crash reports, Store AI conversations in the cloud, AI). Settings sync is on.
Runtime Analysis
Warp Network Monitor logging
Warp’s network monitor does not capture WebSocket (RTC) traffic, despite claiming to log all external communications. This excludes a primary GraphQL subscription channel used for real-time state updates, which continues to transmit user-associated data even when telemetry and AI features are disabled.
This breaks user trust, as it creates a blind spot for communications not surfaced to the user, despite the claim that the network monitor “allows you to view all communications from Warp to external servers to ensure you feel comfortable […]”.
The above is a completeness claim, which contradicts the actual behaviour. The network monitor provides visibility into request/response traffic, but not into the persistent subscription channel that carries the majority of real-time state updates.
Hidden state subscription system
On launch, the client registers a GraphQL subscription named GetWarpDriveUpdates over the RTC WebSocket. The subscription schema (a 12kb document sent as the initial handshake) defines the full scope of data this channel is prepared to receive. This includes direct user identifiers, collaborator email addresses, access control structures, AI conversation metadata, working directories, and workflow metadata (PRs, branches).
Because the network monitor does not capture WebSocket traffic, none of this is visible to the user through Warp’s own network monitor. The subscription remains active regardless of telemetry settings.
1
2
3
4
5
6
7
8
9
10
11
12
permissions {
guests {
accessLevel
subject {
... UserGuest { firebaseUid }
... PendingUserGuest { email }
... TeamGuest { uid }
}
}
anyoneLinkSharing { accessLevel }
space { uid type }
}
As seen above, e-mail addresses of other collaborators may also be transmitted through this packet. The structure represents an ACL model, essentially a live object graph, and multi-user/organization features are baked in, and propagated through the same subscription via RTC.
Additionally, the AI model, which is included even if AI is off, includes fields that may reveal private workflow information, such as workingDirectory, PullRequestArtifact.url and branch.
Certain history actions are also bundled, and while not directly considered telemetry, it can still be seen as activity tracking:
1
2
3
4
5
history {
actions {
BundledActions | SingleAction
}
}
There are also several fields for a time-versioned event system: latestTimestamp, oldestTimestamp, processedAtTimestamp, metadataLastUpdatedTs, revisionTs and taskUpdatedTs.
This is all data that, in theory, could be used to correlate users, collaborators, and workflow context across systems (e.g team user names, e-mails with repository URL, branch). I’ve provided a redacted, readable version of the packet here: GetWarpDriveUpdates.txt.
Incomplete redaction of identifiers
While methods to censor auth tokens are present, it often leaks stable, personal identifiers such as auth token refresh (!), Firebase UIDs and RudderStack UGC key, associated with a user.
The network log, stored at %LOCALAPPDATA%\warp\Warp\data\logs\warp_network.log, was observed to contain OAuth refresh tokens in plaintext. No special file permissions were observed on this path; it sits in a standard user-writable AppData directory with default Windows ACLs, meaning any process running as the same user has read access.
1
Body grant_type=refresh_token&refresh_token=AMf-vBx...[redacted]
The scope of this finding is local: no exfiltration to a remote endpoint was observed, and the token was not tested or replayed. This is noted as a credential hygiene concern rather than an active exploit.
The setting Secret redaction was also enabled for this, showing that there is personal information that can be used to identify a user, not being redacted.
Window focus requests
These requests are triggered by a passive UI event (window focus), not by explicit user action or feature use: GetRequestLimitInfo, GetFeatureModelChoices, GetCloudEnvironmentsQuery, UserGithubInfo. This includes a RudderStack cookie refresh under rl_anonymous_id.
UserGithubInfo is issued on every window focus, even when GitHub is not connected. The query requests repository metadata (installedRepos) when available. This query occurs even with no GitHub integration configured, implying the check is unconditional rather than user-driven.
GetRequestLimitInfo and other AI-related queries are still made despite AI being explicitly off. "x-oz-api-source": "CLOUD_MODE" is also included in the header, implying that cloud-backed features are active at the request layer regardless of user-facing AI settings.
Settings sync
Settings and sync are modelled as server-side objects, tied to a user identity. They require an authenticated user context with a persistent identity (via Firebase), are not purely local toggles, and centrally stored.
BulkCreateObjects is responsible for sending client setting changes to the server. Note that owner.uid denominates a raw Firebase user ID (masked). In this example, the AI option was set to off (Global_IsAnyAIEnabled).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"body": {
"operationName": "BulkCreateObjects",
"query": "mutation BulkCreateObjects(...) { bulkCreateObjects { ... }} [TRUNCATED]",
"variables": {
"input": {
"genericStringObjects": {
"objects": [
{
"clientId": "Client-b928c526-74b5-4884-88e6-47c03285b5a4",
"format": "JsonPreference",
"serializedModel": {
"storage_key": "IsAnyAIEnabled",
"value": false,
"platform": "Global"
},
"uniquenessKey": {
"key": "Global_IsAnyAIEnabled",
"uniquePer": "User"
}
}
],
"owner": {
"uid": "l5bKRgoCRMXO2****Vz53",
"type": "User"
}
[...truncated...]
However, for synchronizing settings from the cloud, the server provides a path for the client to override the toggles, including telemetry options.
The server-side schema includes a telemetrySettings { forceEnabled } field, indicating that telemetry policy can be centrally controlled. Whether this is actively used to override client preferences is not directly observable from client-side analysis alone.
Specifically, GetWorkspacesMetadataForUser also details payment information, telemetryDataCollectionPolicy, ugcDataCollectionPolicy, team member e-mails, AI settings, among other fields.
Static Analysis
Extracted strings
Below are strings extracted from the binary, along with a short explanation.
https://releases.warp.dev- Warp update serverwss://sessions.app.warp.dev- WSS session share featurehttps://warpianwzlfqdq.dataplane.rudderstack.com- RudderStack telemetry entry2uBazVfcqYBDYSOHnqSVx4******- RudderStack ingestion keyIzaSyBdy3O3S9hrdayLJxJ7mriBR4q******- Public Google API key (AIzaSyBdy3O3S9hrdayLJxJ7mriBR4qgU******)https://app.warp.dev/graphql/v2- Main API, most GraphQL lands herewss://rtc.app.warp.dev/graphql/v2- RTC for GraphQL, same as HTTPhttps://oz.warp.dev- AI and agentic APIhttps://******1da0714f55a93ee4624825f9ec@o540343.ingest.sentry.io/5658526- Sentry DSN (public identifier for crash reporting ingestion).
Other interesting findings for the purpose of reverse-engineering.
protobuf,gRpC- Merkle field names:
total_sync_duration,flushed_node_count,flushed_fragment_count,total_fragment_size_bytes,cache_population_error,file_traversal_duration,merkle_tree_parse_duration - Rust-related:
ai\src\telemetry.rs,ui\src\app_focus_telemetry.rs,alloc::boxed::Box<dyn warp_core::telemetry::TelemetryContextProvider>.
Registry artifacts
Warp also relies heavily on registry for its Windows build. Here is a dump of keys and values found in [HKEY_CURRENT_USER\Software\Warp.dev\Warp].
Some values were anonymized or in brevity:
ExperimentIdcan be used to persist user correlation (ID)EnteredAgentModeNumTimes,AgentModeSetupBannerShownForRepoPathstracks usage pattern as well as repositoriesMCPExecutionPathin particular was just a mirror of $PATH.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
ExperimentId (String) = 79147d64-bfc2-xxxx-xxxx-3b021525a4d9
TelemetryEnabled (String) = false
CrashReportingEnabled (String) = false
CloudConversationStorageEnabled (String) = false
ShouldAddAgentModeChip (String) = false
HasInitializedDefaultSecretRegexes (String) = true
FontSize (String) = 16.0
InputBoxTypeSetting (String) = "Universal"
NLDInTerminalEnabled (String) = true
IsSettingsSyncEnabled (String) = true
AvailableLLMs (String) = { ... }
DidNonAnonymousUserLogIn (String) = true
DidShowOzLaunchModal (String) = true
AIRequestLimitInfo (String) = { ... }
AIRequestQuotaInfoSetting (String) = { ... }
HasAutoOpenedWelcomeFolder (String) = true
SystemTheme (String) = false
Theme (String) = "Dark"
HasAutoOpenedConversationList (String) = true
ReceivedReferralTheme (String) = "Inactive"
AIAssistantRequestLimitInfo (String) = { ... }
MCPExecutionPath (String) = $PATH
EnteredAgentModeNumTimes (String) = 0
WelcomeTipsFeaturesUsed (String) = [{"Action":"SplitPane"},{"Hint":"BlockAction"},{"Hint":"CreateBlock"},{"Hint":"BlockSelect"}]
AliasExpansionBannerSeen (String) = true
SafeModeEnabled (String) = true
OverrideOpacity (String) = 100
OverrideBlurTexture (String) = false
NotebookFontSize (String) = 14.0
Spacing (String) = "Normal"
ChangelogVersions (String) = {"v0.2026.02.18.08.22.stable_02":true}
DismissedCodeToolbeltNewFeaturePopup (String) = true
FontName (String) = "Hack"
AIFontName (String) = "Hack"
MatchAIFont (String) = false
Notifications (String) = {"mode":"Enabled","is_long_running_enabled":true,"long_running_threshold":{"secs":30,"nanos":0},"is_password_prompt_enabled":true,"is_agent_task_completed_enabled":true,"is_needs_attention_enabled":true,"play_notification_sound":true}
OpenWindowsAtCustomSize (String) = false
AutosuggestionAcceptedCount (String) = 2
AgentModeSetupBannerShownForRepoPaths (String) = ["C:\\Data\\Dev\\...\\git"]
PSPath (String) = Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Warp.dev\Warp
PSParentPath (String) = Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Warp.dev
PSChildName (String) = Warp
PSDrive (PSDriveInfo) = HKCU
PSProvider (ProviderInfo) = Microsoft.PowerShell.Core\Registry
Key Functions
The following is a description of the RTC WSS chain and offsets found that were used for reverse-engineering.
- Literal: 0x14932C874 (RVA 0x932C874) =
wss://rtc.app.warp.dev/graphql/v2 - Direct refs: 0x141B19514, 0x141B1951B in FUN_141B19400 (RVA 0x1B19400)
- Caller path: __scrt_common_main_seh -> FUN_141B19680 (RVA 0x1B19680) -> FUN_141B1EE00
- Config copy sink: FUN_14671D540 (RVA 0x671D540) copies struct to globals
- WSS globals: DAT_150B81058 (ptr, RVA 0x10B81058), DAT_150B81060 (len, RVA 0x10B81060)
- Getter: FUN_14671C9C0 (RVA 0x671C9C0)
- Hot sites: read 0x142B7255E (RVA 0x2B7255E), write 0x142B72581 (RVA 0x2B72581)
- Dynamic parser: FUN_14671DF60 (RVA 0x671DF60, handles ws_server_url keys)
Lessons Learned
Warp’s architecture relies on persistent identity, server-synchronized state, and real-time subscriptions.
While these are not inherently problematic, the network monitor’s incomplete visibility undermines its stated goal of transparency, making it difficult for users to independently verify the full scope of data being transmitted. Users relying on the network monitor as a trust mechanism should be aware of this blind spot.

