[{"data":1,"prerenderedAt":971},["ShallowReactive",2],{"page-\u002Fsecurity":3},{"id":4,"title":5,"body":6,"date":961,"description":962,"extension":963,"image":961,"meta":964,"navigation":965,"ogImage":961,"path":966,"robots":961,"schemaOrg":961,"seo":967,"sitemap":968,"stem":969,"tags":961,"__hash__":970},"content\u002FSECURITY.md","Security Overview",{"type":7,"value":8,"toc":925},"minimark",[9,14,18,21,26,29,31,35,55,57,61,66,73,117,125,129,148,164,166,170,173,177,184,188,201,203,207,210,212,216,220,223,233,237,309,311,315,319,324,327,329,336,339,430,432,439,442,529,531,538,541,583,590,592,596,699,703,710,714,728,730,734,752,754,758,761,763,767,771,797,801,821,823,827,830,916,921],[10,11,13],"h1",{"id":12},"postpilot-security-overview","PostPilot Security Overview",[15,16,17],"p",{},"This document describes how PostPilot handles your data, what leaves your machine, and what security practices are in place. It is intended for users who want to review the app before using it with sensitive credentials.",[19,20],"hr",{},[22,23,25],"h2",{"id":24},"_1-architecture","1. Architecture",[15,27,28],{},"PostPilot is a local-first desktop application built with Tauri (Rust backend) and a Nuxt frontend. There is no PostPilot cloud backend involved in your API calls, database queries, or data inspection work. All core operations run entirely on your machine.",[19,30],{},[22,32,34],{"id":33},"_2-data-flow","2. Data Flow",[36,37,38,46,52],"ul",{},[39,40,41,45],"li",{},[42,43,44],"strong",{},"HTTP requests"," go directly from your machine to the target server. PostPilot never sees the payload, headers, or response content.",[39,47,48,51],{},[42,49,50],{},"Database queries"," execute directly from your machine to your database server — no data is routed through PostPilot infrastructure.",[39,53,54],{},"No request or response content is sent to PostPilot servers, logged to disk, or stored externally.",[19,56],{},[22,58,60],{"id":59},"_3-credential-storage","3. Credential Storage",[62,63,65],"h3",{"id":64},"database-passwords","Database Passwords",[15,67,68,69,72],{},"Database passwords are stored in your OS-native secure storage and are ",[42,70,71],{},"never written to disk in plaintext",":",[74,75,76,89],"table",{},[77,78,79],"thead",{},[80,81,82,86],"tr",{},[83,84,85],"th",{},"Platform",[83,87,88],{},"Storage",[90,91,92,101,109],"tbody",{},[80,93,94,98],{},[95,96,97],"td",{},"macOS",[95,99,100],{},"Keychain Access",[80,102,103,106],{},[95,104,105],{},"Windows",[95,107,108],{},"Credential Manager",[80,110,111,114],{},[95,112,113],{},"Linux",[95,115,116],{},"Secret Service (GNOME Keyring \u002F KWallet)",[15,118,119,120,124],{},"Workspace connection files contain only ",[121,122,123],"code",{},"{ \"password\": { \"keychain\": true } }",". The actual password lives only in the OS keychain, retrieved at query time.",[62,126,128],{"id":127},"environment-variables","Environment Variables",[15,130,131,132,135,136,139,140,143,144,147],{},"Environment variables — including API keys, tokens, and any secret stored as ",[121,133,134],{},"{{variableName}}"," — are saved as ",[42,137,138],{},"plain JSON files"," inside your workspace folder under the ",[121,141,142],{},"environments\u002F"," directory. They are ",[42,145,146],{},"not encrypted at rest",".",[149,150,151],"blockquote",{},[15,152,153,156,157,159,160,163],{},[42,154,155],{},"Recommendation",": If you version-control your workspace with Git, add ",[121,158,142],{}," to your ",[121,161,162],{},".gitignore"," to avoid accidentally committing secrets.",[19,165],{},[22,167,169],{"id":168},"_4-network-communication","4. Network Communication",[15,171,172],{},"PostPilot makes outbound network requests in two situations only:",[62,174,176],{"id":175},"your-api-calls","Your API Calls",[15,178,179,180,183],{},"HTTP requests you execute in PostPilot go directly from your machine to the target URL using the system network stack (Rust ",[121,181,182],{},"reqwest"," library). No content is routed through PostPilot servers. No request or response data is written to disk or app logs.",[62,185,187],{"id":186},"license-verification","License Verification",[15,189,190,191,194,195,200],{},"On every app launch, PostPilot contacts ",[121,192,193],{},"https:\u002F\u002Flicense.postpilot.dev\u002Fapi"," to verify your license. See ",[196,197,199],"a",{"href":198},"#7-license-service","Section 7 — License Service"," for the full breakdown of what is sent.",[19,202],{},[22,204,206],{"id":205},"_5-offline-capability","5. Offline Capability",[15,208,209],{},"Editing kits, running API requests, executing database queries, and inspecting data all work offline. License verification requires an internet connection on app startup. If the network is unavailable, the app will inform you.",[19,211],{},[22,213,215],{"id":214},"_6-local-data-storage","6. Local Data Storage",[62,217,219],{"id":218},"file-structure-desktop","File Structure (Desktop)",[15,221,222],{},"Workspace data is stored as human-readable JSON files in the folder you select when creating a workspace:",[224,225,230],"pre",{"className":226,"code":228,"language":229},[227],"language-text","my-workspace\u002F\n├── workspace.json\n├── environments\u002F                   ← Variable values stored here in plaintext\n│   └── \u003Cenv-name>\u002F\n│       └── environment-variables.json\n├── collections\u002F                    ← HTTP and DB kit definitions (no secrets)\n│   └── \u003Ccollection>\u002F\n│       └── *.http.json\n└── database-connections\u002F           ← Connection metadata (no passwords)\n    └── *.connection.json\n","text",[121,231,228],{"__ignoreMap":232},"",[62,234,236],{"id":235},"what-is-and-isnt-encrypted-at-rest","What Is and Isn't Encrypted at Rest",[74,238,239,252],{},[77,240,241],{},[80,242,243,246,249],{},[83,244,245],{},"Data",[83,247,248],{},"Where",[83,250,251],{},"Encrypted?",[90,253,254,265,278,288,299],{},[80,255,256,259,262],{},[95,257,258],{},"Database passwords",[95,260,261],{},"OS Keychain",[95,263,264],{},"Yes (OS-managed)",[80,266,267,270,273],{},[95,268,269],{},"Environment variables",[95,271,272],{},"Workspace JSON file",[95,274,275],{},[42,276,277],{},"No — plaintext",[80,279,280,283,285],{},[95,281,282],{},"HTTP kit content",[95,284,272],{},[95,286,287],{},"No",[80,289,290,293,296],{},[95,291,292],{},"License key",[95,294,295],{},"App data directory",[95,297,298],{},"No (not a sensitive secret)",[80,300,301,304,307],{},[95,302,303],{},"Device key (for license)",[95,305,306],{},"OS secure storage",[95,308,264],{},[19,310],{},[22,312,314],{"id":313},"_7-license-service","7. License Service",[62,316,318],{"id":317},"endpoint","Endpoint",[15,320,321,322],{},"All license operations contact: ",[121,323,193],{},[15,325,326],{},"The app makes three types of requests to this endpoint:",[19,328],{},[62,330,332,333],{"id":331},"trial-creation-post-licensestrial","Trial Creation — ",[121,334,335],{},"POST \u002Flicenses\u002Ftrial",[15,337,338],{},"Sent once when starting a free trial.",[224,340,344],{"className":341,"code":342,"language":343,"meta":232,"style":232},"language-json shiki shiki-themes github-dark","{\n  \"device\": {\n    \"id\": \"\u003C32-char device ID, derived from public key hash>\",\n    \"publicKey\": \"\u003CECDSA P-256 public key, base64 DER encoded>\",\n    \"keyOrigin\": \"OS_SECURE\",\n    \"keyType\": \"ECDSA_P256\"\n  }\n}\n","json",[121,345,346,355,365,381,394,407,418,424],{"__ignoreMap":232},[347,348,351],"span",{"class":349,"line":350},"line",1,[347,352,354],{"class":353},"s95oV","{\n",[347,356,358,362],{"class":349,"line":357},2,[347,359,361],{"class":360},"sDLfK","  \"device\"",[347,363,364],{"class":353},": {\n",[347,366,368,371,374,378],{"class":349,"line":367},3,[347,369,370],{"class":360},"    \"id\"",[347,372,373],{"class":353},": ",[347,375,377],{"class":376},"sU2Wk","\"\u003C32-char device ID, derived from public key hash>\"",[347,379,380],{"class":353},",\n",[347,382,384,387,389,392],{"class":349,"line":383},4,[347,385,386],{"class":360},"    \"publicKey\"",[347,388,373],{"class":353},[347,390,391],{"class":376},"\"\u003CECDSA P-256 public key, base64 DER encoded>\"",[347,393,380],{"class":353},[347,395,397,400,402,405],{"class":349,"line":396},5,[347,398,399],{"class":360},"    \"keyOrigin\"",[347,401,373],{"class":353},[347,403,404],{"class":376},"\"OS_SECURE\"",[347,406,380],{"class":353},[347,408,410,413,415],{"class":349,"line":409},6,[347,411,412],{"class":360},"    \"keyType\"",[347,414,373],{"class":353},[347,416,417],{"class":376},"\"ECDSA_P256\"\n",[347,419,421],{"class":349,"line":420},7,[347,422,423],{"class":353},"  }\n",[347,425,427],{"class":349,"line":426},8,[347,428,429],{"class":353},"}\n",[19,431],{},[62,433,435,436],{"id":434},"license-activation-post-licensesactivate","License Activation — ",[121,437,438],{},"POST \u002Flicenses\u002Factivate",[15,440,441],{},"Sent once when activating a purchased license on a device.",[224,443,445],{"className":341,"code":444,"language":343,"meta":232,"style":232},"{\n  \"licenseKey\": \"XXXX-XXXX-XXXX-XXXX\",\n  \"device\": {\n    \"id\": \"\u003Cdevice ID>\",\n    \"publicKey\": \"\u003CECDSA P-256 public key, base64 DER encoded>\",\n    \"keyOrigin\": \"OS_SECURE\",\n    \"keyType\": \"ECDSA_P256\"\n  },\n  \"appVersion\": \"1.x.x\"\n}\n",[121,446,447,451,463,469,480,490,500,508,513,524],{"__ignoreMap":232},[347,448,449],{"class":349,"line":350},[347,450,354],{"class":353},[347,452,453,456,458,461],{"class":349,"line":357},[347,454,455],{"class":360},"  \"licenseKey\"",[347,457,373],{"class":353},[347,459,460],{"class":376},"\"XXXX-XXXX-XXXX-XXXX\"",[347,462,380],{"class":353},[347,464,465,467],{"class":349,"line":367},[347,466,361],{"class":360},[347,468,364],{"class":353},[347,470,471,473,475,478],{"class":349,"line":383},[347,472,370],{"class":360},[347,474,373],{"class":353},[347,476,477],{"class":376},"\"\u003Cdevice ID>\"",[347,479,380],{"class":353},[347,481,482,484,486,488],{"class":349,"line":396},[347,483,386],{"class":360},[347,485,373],{"class":353},[347,487,391],{"class":376},[347,489,380],{"class":353},[347,491,492,494,496,498],{"class":349,"line":409},[347,493,399],{"class":360},[347,495,373],{"class":353},[347,497,404],{"class":376},[347,499,380],{"class":353},[347,501,502,504,506],{"class":349,"line":420},[347,503,412],{"class":360},[347,505,373],{"class":353},[347,507,417],{"class":376},[347,509,510],{"class":349,"line":426},[347,511,512],{"class":353},"  },\n",[347,514,516,519,521],{"class":349,"line":515},9,[347,517,518],{"class":360},"  \"appVersion\"",[347,520,373],{"class":353},[347,522,523],{"class":376},"\"1.x.x\"\n",[347,525,527],{"class":349,"line":526},10,[347,528,429],{"class":353},[19,530],{},[62,532,534,535],{"id":533},"license-verification-post-licensesverify","License Verification — ",[121,536,537],{},"POST \u002Flicenses\u002Fverify",[15,539,540],{},"Sent on every app launch to confirm the license is still active.",[224,542,544],{"className":341,"code":543,"language":343,"meta":232,"style":232},"{\n  \"licenseKey\": \"XXXX-XXXX-XXXX-XXXX\",\n  \"deviceId\": \"\u003Cdevice ID>\",\n  \"appVersion\": \"1.x.x\"\n}\n",[121,545,546,550,560,571,579],{"__ignoreMap":232},[347,547,548],{"class":349,"line":350},[347,549,354],{"class":353},[347,551,552,554,556,558],{"class":349,"line":357},[347,553,455],{"class":360},[347,555,373],{"class":353},[347,557,460],{"class":376},[347,559,380],{"class":353},[347,561,562,565,567,569],{"class":349,"line":367},[347,563,564],{"class":360},"  \"deviceId\"",[347,566,373],{"class":353},[347,568,477],{"class":376},[347,570,380],{"class":353},[347,572,573,575,577],{"class":349,"line":383},[347,574,518],{"class":360},[347,576,373],{"class":353},[347,578,523],{"class":376},[347,580,581],{"class":349,"line":396},[347,582,429],{"class":353},[15,584,585,586,589],{},"This request is signed with your device's private key (stored in OS secure storage). The private key itself is ",[42,587,588],{},"never transmitted"," — only the cryptographic signature is sent, allowing the server to verify your device without ever seeing the key.",[19,591],{},[62,593,595],{"id":594},"what-is-stored-on-our-server","What Is Stored on Our Server",[74,597,598,610],{},[77,599,600],{},[80,601,602,604,607],{},[83,603,245],{},[83,605,606],{},"Stored?",[83,608,609],{},"Purpose",[90,611,612,623,633,643,653,663,672,681,690],{},[80,613,614,617,620],{},[95,615,616],{},"License key + status",[95,618,619],{},"Yes",[95,621,622],{},"Track whether license is active, expired, or suspended",[80,624,625,628,630],{},[95,626,627],{},"Device ID (public key hash)",[95,629,619],{},[95,631,632],{},"Bind license to your device",[80,634,635,638,640],{},[95,636,637],{},"Device public key",[95,639,619],{},[95,641,642],{},"Verify cryptographic signatures on future requests",[80,644,645,648,650],{},[95,646,647],{},"App version at activation",[95,649,619],{},[95,651,652],{},"Version enforcement",[80,654,655,658,660],{},[95,656,657],{},"Request\u002Fresponse payloads",[95,659,287],{},[95,661,662],{},"—",[80,664,665,668,670],{},[95,666,667],{},"API keys or environment variables",[95,669,287],{},[95,671,662],{},[80,673,674,677,679],{},[95,675,676],{},"Hardware identifiers",[95,678,287],{},[95,680,662],{},[80,682,683,686,688],{},[95,684,685],{},"IP address logs",[95,687,287],{},[95,689,662],{},[80,691,692,695,697],{},[95,693,694],{},"Usage analytics",[95,696,287],{},[95,698,662],{},[62,700,702],{"id":701},"device-identity","Device Identity",[15,704,705,706,709],{},"Your device ID is derived as ",[121,707,708],{},"hex(sha256(publicKey)[0..16])"," — a 32-character opaque identifier computed from your device's cryptographic public key. It does not directly expose any hardware identifiers.",[62,711,713],{"id":712},"data-retention","Data Retention",[36,715,716,722],{},[39,717,718,721],{},[42,719,720],{},"Trial licenses",": License records are stored to enforce the one-trial-per-device policy (trials are valid for 14 days; a new trial is available after 6 months). We do not yet automatically delete these records — this is a known gap we plan to address with a 6-month retention policy.",[39,723,724,727],{},[42,725,726],{},"Perpetual licenses",": Stored while your license is active. To request deletion, contact us directly.",[19,729],{},[22,731,733],{"id":732},"_8-telemetry-and-analytics","8. Telemetry and Analytics",[36,735,736,742],{},[39,737,738,741],{},[42,739,740],{},"Desktop app",": No telemetry, crash reporting, or usage analytics are collected.",[39,743,744,747,748,751],{},[42,745,746],{},"Web version"," (postpilot.dev): Vercel Analytics is used for ",[42,749,750],{},"anonymous page visit counts only",". No personal data, session behavior, or feature usage is tracked.",[19,753],{},[22,755,757],{"id":756},"_9-auto-update","9. Auto-Update",[15,759,760],{},"The desktop app does not auto-update. There is no background update process. Updates are published to the website and must be downloaded and installed manually by the user.",[19,762],{},[22,764,766],{"id":765},"_10-threat-model","10. Threat Model",[62,768,770],{"id":769},"what-postpilot-protects-against","What PostPilot Protects Against",[36,772,773,779,785,791],{},[39,774,775,778],{},[42,776,777],{},"Network interception of API\u002FDB traffic",": Requests never pass through PostPilot servers.",[39,780,781,784],{},[42,782,783],{},"Database password exposure",": Stored in the OS keychain — never written to any file.",[39,786,787,790],{},[42,788,789],{},"License response tampering",": Server responses are cryptographically signed with an RSA key embedded in the app binary. The app rejects responses that fail signature verification.",[39,792,793,796],{},[42,794,795],{},"License replay attacks",": Each verification uses a single-use nonce, so captured requests cannot be replayed.",[62,798,800],{"id":799},"what-postpilot-does-not-protect-against","What PostPilot Does Not Protect Against",[36,802,803,809,815],{},[39,804,805,808],{},[42,806,807],{},"A fully compromised OS",": If your operating system or user account is compromised, files in your workspace folder (including environment variable files) are accessible to the attacker.",[39,810,811,814],{},[42,812,813],{},"Environment variable exposure via filesystem access",": These files are plaintext JSON. Anyone with read access to your workspace folder can read them.",[39,816,817,820],{},[42,818,819],{},"Browser-level threats on the web version",": localStorage is readable via browser devtools and accessible to scripts running on the same origin.",[19,822],{},[22,824,826],{"id":825},"_11-web-version","11. Web Version",[15,828,829],{},"The browser-based version of PostPilot has a different security profile from the desktop app:",[74,831,832,845],{},[77,833,834],{},[80,835,836,839,842],{},[83,837,838],{},"Aspect",[83,840,841],{},"Desktop",[83,843,844],{},"Web",[90,846,847,858,869,880,894,905],{},[80,848,849,852,855],{},[95,850,851],{},"Data storage",[95,853,854],{},"Filesystem (workspace folder)",[95,856,857],{},"Browser localStorage",[80,859,860,863,866],{},[95,861,862],{},"Credential storage",[95,864,865],{},"OS Keychain for DB passwords",[95,867,868],{},"No keychain — all localStorage",[80,870,871,874,877],{},[95,872,873],{},"Database clients",[95,875,876],{},"Supported",[95,878,879],{},"Not supported",[80,881,882,885,891],{},[95,883,884],{},"HTTP transport",[95,886,887,888,890],{},"Rust ",[121,889,182],{}," (direct)",[95,892,893],{},"Browser Axios (CORS applies)",[80,895,896,899,902],{},[95,897,898],{},"Analytics",[95,900,901],{},"None",[95,903,904],{},"Vercel anonymous page visits",[80,906,907,910,913],{},[95,908,909],{},"Updates",[95,911,912],{},"Manual download",[95,914,915],{},"Always latest deployed version",[15,917,918,920],{},[42,919,155],{},": For work involving production credentials, database connections, or sensitive API keys, use the desktop app. The web version does not have access to OS-level secure storage.",[922,923,924],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":232,"searchDepth":357,"depth":357,"links":926},[927,928,929,933,937,938,942,954,955,956,960],{"id":24,"depth":357,"text":25},{"id":33,"depth":357,"text":34},{"id":59,"depth":357,"text":60,"children":930},[931,932],{"id":64,"depth":367,"text":65},{"id":127,"depth":367,"text":128},{"id":168,"depth":357,"text":169,"children":934},[935,936],{"id":175,"depth":367,"text":176},{"id":186,"depth":367,"text":187},{"id":205,"depth":357,"text":206},{"id":214,"depth":357,"text":215,"children":939},[940,941],{"id":218,"depth":367,"text":219},{"id":235,"depth":367,"text":236},{"id":313,"depth":357,"text":314,"children":943},[944,945,947,949,951,952,953],{"id":317,"depth":367,"text":318},{"id":331,"depth":367,"text":946},"Trial Creation — POST \u002Flicenses\u002Ftrial",{"id":434,"depth":367,"text":948},"License Activation — POST \u002Flicenses\u002Factivate",{"id":533,"depth":367,"text":950},"License Verification — POST \u002Flicenses\u002Fverify",{"id":594,"depth":367,"text":595},{"id":701,"depth":367,"text":702},{"id":712,"depth":367,"text":713},{"id":732,"depth":357,"text":733},{"id":756,"depth":357,"text":757},{"id":765,"depth":357,"text":766,"children":957},[958,959],{"id":769,"depth":367,"text":770},{"id":799,"depth":367,"text":800},{"id":825,"depth":357,"text":826},null,"How PostPilot handles your data, what leaves your machine, and the security practices in place — for users who want to review the app before using it with sensitive credentials.","md",{},true,"\u002Fsecurity",{"title":5,"description":962},{"loc":966},"SECURITY","wAC1H79OMnvTCg3O5YAzA45IcRzDgrn1JJan4AH12kk",1776790862475]