🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
Sve rute OmniRoute API-ja za upravljanje klasificirane su u jedan od tri nivoa
zaštite. Klasifikacija je statična, definirana u src/server/authz/routeGuard.ts
i procjenjuje se prije izvršavanja bilo koje druge grane autentifikacije.
Provedeno od strane: isLocalOnlyPath(path) → provjera loopback hosta
Zaobilaženje: Nema podrazumijevano. Usko izuzeće za putanje u
LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES kada zahtjev nosi važeći
API ključ sa manage opsegom (pogledajte Izuzeće za opseg upravljanja).
Ove rute pokreću podređene procese ili izvršavaju runtime kod. Izlaganje istih saobraćaju koji nije loopback omogućilo bi napadaču koji je dobio važeći JWT (npr. putem Cloudflared/Ngrok tunela) da pokrene stvaranje procesa — poznatu CVE klasu (GHSA-fhh6-4qxv-rpqj).
Šta je GHSA-fhh6-4qxv-rpqj (klasa napada): server za upravljanje/agenta
izlaže krajnju tačku koja pokreće podproces (npm install, node, pretraživač,
proxy, git, tar, …). Ako je ta krajnja tačka dostupna sa vanjskog hosta — jer
je operator postavio OmniRoute iza nginx/Cloudflare/Tailscale tunela i JWT je
procurio, ili je autentifikacija bila pogrešno konfigurisana — napadač pretvara
"pozivanje API-ja" u "izvršavanje komande na hostu" (daljinsko izvršavanje koda).
OmniRoute ovo sprečava provođenjem bezuslovne provjere loopback hosta, prije
bilo kakve provjere autentifikacije, na svakoj ruti koja može pokrenuti proces:
procurjeli token preko tunela i dalje ne može doći do pokretanja.
Potpuni LOCAL_ONLY skup. Autoritetni izvor su
LOCAL_ONLY_API_PREFIXES / LOCAL_ONLY_API_PATTERNS u
src/server/authz/routeGuard.ts; tabela ispod odražava trenutno stanje.
check-route-guard-membership kapija nabraja svaki route.ts pod
prefiksima koji mogu pokrenuti procese i ne uspijeva CI ako bilo koji nije
klasifikovan kao samo-lokalni.
| Prefix / pattern | Zašto je samo lokalno |
|---|---|
/api/mcp/ |
MCP server — pokreće stdio mostove + SSE rukovaoce |
/api/cli-tools/runtime/ |
CLI okruženje za izvršavanje alata — izvršava proizvoljni kod dodataka |
/api/cli-tools/{omp,letta,grok-build,forge,jcode,qwen}-settings |
Pisci postavki po alatu koji mogu mijenjati binarne datoteke/konfiguraciju alata na hostu |
/api/cli-tools/{claude,cline,codewhale,codex,crush,deepseek-tui,droid,kilo,openclaw,pi,smelt}-settings |
Isto pokretanje getCliRuntimeStatus() kao i šest gore navedenih srodnih (GHSA-35fw-cv32-2373) |
/api/cli-tools/{all-statuses,status,detect} |
CLI sonde za inventar — pokreću command -v / --version po alatu (GHSA-35fw-cv32-2373) |
/api/cli-tools/antigravity-mitm |
Kontrola Antigravity MITM proxyja (pokreće/usmjerava sistemski proxy) |
/api/modality-bridge/video/ |
Stroga trusted-loopback Video Bridge runtime sonda i interni most za ekstrakciju |
/api/services/ |
Ugrađene usluge (9Router / CLIProxy / Bifrost / Mux / Dario) — npm install + pokretanje |
/dashboard/providers/services/ |
Reverzni proxy za korisnička sučelja ugrađenih usluga |
/api/tunnels/cloudflared |
Instalira/pokreće cloudflared binarnu datoteku |
/api/tunnels/tailscale/{install,enable,disable,login,start-daemon} |
Instalira/kontrolira tailscaled na hostu |
/api/copilot/ |
Neautentificirani LLM drajver — samo CLI po defaultu |
/api/tools/agent-bridge/ |
AgentBridge — pokreće MITM server + DNS izmjene |
/api/tools/traffic-inspector/ |
Inspektor prometa — http-proxy slušatelj + sistemski proxy |
/api/settings/mitm |
Omogućava MITM presretanje (stanje proxyja na nivou sistema) |
/api/issue-agent/ |
Agent za probleme — pokreće lokalne alate protiv repozitorija |
/api/plugins/, /api/plugins |
Dodaci — učitavaju/izvršavaju se putem worker_threads + child_process |
/api/middleware/ |
Korisnički middleware — učitava/izvršava operatorski kod unutar procesa |
/api/system/version |
Automatsko ažuriranje (samo POST; GET/HEAD/OPTIONS izuzeti) — pokreće git checkout + npm install |
/api/db-backups/exportAll |
Pokreće tar za arhivu izvoza |
/api/local/ |
Lokalni pokretači jednim klikom (Redis danas) — pokreće podman/docker |
/api/headroom/start, /api/headroom/stop |
Životni ciklus Headroom proxyja — pokreće python CLI / signalizira PID |
/api/jobs, /api/jobs/ |
Kontrola pokretača poslova — izvršava zakazani rad na strani hosta |
/api/oauth/cursor/auto-import |
execFile("which", ["cursor"]) prije uvoza vjerodajnica |
/api/oauth/kiro/auto-import |
Čita Kiro CLI datoteke vjerodajnica sa hosta |
/api/skills/collect/ |
Prikupljanje vještina — detektira/instalira lokalne alate |
/api/skills/install, /api/skills/executions |
Registracija + izvršavanje rukovaoca vještinama — doseže pokretanje sandbox kontejnera (GHSA-jx89) |
/api/discovery/ |
Lokalne sonde za otkrivanje mreže/provajdera |
/api/vnc-session (VNC_ROUTE_PREFIX) |
Pokreće preglednik s grafičkim sučeljem + VNC sesiju za interaktivne prijave |
/api/acp/agents |
ACP — otkriva i pokreće lokalne binarne datoteke CLI agenta |
/api/resilience/connections |
JSON otpornosti po računu (hlađenje, prekid, zaključavanje). HTML nadzorne ploče nije samo lokalni. |
/api/providers/cursor/agent-availability |
Provjera poticaja za instalaciju nadzorne ploče — pokreće cursor-agent status --format json |
/api/providers/{id}/login (regex) |
Pokreće Playwright Chromium s grafičkim sučeljem za prijavu putem web kolačića |
/api/providers/volcengine-plan/connect (regex) |
Ručni tok s grafičkim sučeljem + automatska prijava telefonom/SMS-om bazirana na sesiji (pokreće Playwright) |
/api/providers/{id}/refresh-cursor (regex) |
Ručno obnavljanje Cursor sesije — potiče cursor-agent |
/api/providers/{id}/chatgpt-web-codex-doctor (regex) |
Dijagnosticira lokalnu instalaciju Codex CLI-ja (pokreće binarnu datoteku) |
Odgovor na kršenje: 403 LOCAL_ONLY
Podskup LOCAL_ONLY putanja MOŽE biti dostupan i izvan loopbacka ako i
samo ako zahtjev nosi Authorization: Bearer <api-key> čiji
metapodaci uključuju opseg manage (ili admin). Izuzeće je eksplicitno
ograničeno po putanji putem LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES, tako da
zadana vrijednost za bilo koju novu LOCAL_ONLY putanju ostaje strogi loopback.
Neautentificirani zahtjevi i zahtjevi s ključevima koji nemaju manage opseg
i dalje se odbijaju s 403 LOCAL_ONLY.
Danas je jedini prefiks koji se može zaobići /api/mcp/. /api/cli-tools/runtime/ i
/api/services/ su namjerno isključeni jer mogu pokrenuti proizvoljne
podprocese (npm install, node), što je točno klasa CVE-a koju
LOCAL_ONLY sloj sprječava.
#7895 — mcp:connect uski opseg: izuzeće za /api/mcp/ TAKOĐER prihvaća
Bearer ključ koji sadrži uski mcp:connect opseg
(src/shared/constants/managementScopes.ts::MCP_CONNECT_SCOPE), provjeren putem
hasMcpConnectOrManageScope() u src/server/authz/policies/management.ts.
Ovo je ograničeno SAMO na /api/mcp/ — mcp:connect ne daje ništa na bilo
kojoj drugoj ruti upravljanja (uključujući svaki drugi LOCAL_ONLY prefiks za
zaobilaženje, ako se ikada doda), i namjerno je isključeno iz
MANAGEMENT_API_KEY_SCOPES. Ključ koji sadrži manage/admin i dalje prolazi
izuzeće točno kao i prije; mcp:connect je alternativa s nižim privilegijama
za udaljene pozivatelje samo za MCP koji ne bi trebali trebati širok pristup
upravljanju.
| Zahtjev | Putanja | Rezultat |
|---|---|---|
| Izvan loopbacka, bez Bearer ključa | /api/mcp/* |
403 LOCAL_ONLY |
Izvan loopbacka, Bearer ključ s opsegom manage |
/api/mcp/* |
Dozvoljeno |
Izvan loopbacka, Bearer ključ s opsegom mcp:connect |
/api/mcp/* |
Dozvoljeno |
Izvan loopbacka, Bearer ključ bez manage/mcp:connect |
/api/mcp/* |
403 LOCAL_ONLY |
Izvan loopbacka, Bearer ključ s opsegom mcp:connect |
/api/cli-tools/runtime/* |
403 LOCAL_ONLY |
Izvan loopbacka, Bearer ključ s opsegom manage |
/api/cli-tools/runtime/* |
403 LOCAL_ONLY |
| Loopback, bilo koji/bez Bearer ključa | bilo koji LOCAL_ONLY |
Dozvoljeno (provjera prolazi) |
Ako pokrećete OmniRoute iza obrnutog proxyja ili tunela (nginx, Caddy, Cloudflare
Tunnel, Tailscale, Ngrok), provjera loopbacka i dalje štiti gore navedene rute
koje mogu pokrenuti procese — zahtjev čija klijentska adresa nije loopback
odbija se s 403 LOCAL_ONLY prije pokretanja autentifikacije, tako da
procurjeli JWT ne može doći do pokretanja procesa. Dvije odgovornosti operatera
ostaju:
- Nemojte "popravljati" 403 krivotvorenjem klijentske IP adrese kao loopback. Postavljanje
X-Forwarded-For: 127.0.0.1, ili proxy koji prepisuje izvornu adresu na loopback, ponovno otvara točno onu klasu RCE-a koju ovaj sloj zatvara. Izložite nadzornu ploču/API putem proxyja — nikada rute koje mogu pokrenuti procese. - Održavajte zaobilaženje opsega upravljanja minimalnim. Samo
/api/mcp/se može zaobići, i to samo s API ključem s opsegommanage.SPAWN_CAPABLE_PREFIXESse nikada ne mogu dodati na listu zaobilaženja — zod shema ih odbija, aisLocalOnlyBypassableByManageScopeih odbija u runtimeu (dubinska obrana), što nadzorna ploča podrazumijeva pod "ne može se učiniti zaobilaznim". Rute s dinamičkim segmentima i statičkim putanjama koje mogu pokrenuti procese pod/api/providers/(npr./login,/refresh-cursor) pokrivene su regex-baziranimSPAWN_CAPABLE_PATTERNS/SPAWN_CAPABLE_PATTERN_ANCESTORSpratiocem usrc/shared/constants/spawnCapablePrefixes.ts, a ne ravnimSPAWN_CAPABLE_PREFIXESnizom — ravni niz bi morao pokriti cijeli/api/providers/prefiks da bi ih uhvatio, preširoko proširujući stablo ruta koje udaljene nadzorne ploče legitimno koriste za CRUD pružatelja.
Revizija pristupa — za provjeru da ništa izvan hosta ne doseže ove rute:
- Otvorite Inventar autorizacije na
/dashboard/settings/security: prikazuje listu prefiksa LOCAL_ONLY uživo, koji prefiksi se mogu zaobići, i skup sposobnih za pokretanje u vrijeme kompilacije ("ne mogu se učiniti zaobilaznim"). - Pretražite svoje reverse-proxy / pristupne logove za gore navedene prefikse uparene sa
klijentskom adresom koja nije loopback. Svaki takav pogodak koji je vratio
200umjesto403 LOCAL_ONLYznači da proxy maskira stvarnu IP adresu klijenta — popravite proxy. 403 LOCAL_ONLYu OmniRoute logovima za jednu od ovih putanja je čuvar koji radi kako je predviđeno, a ne greška koju treba potisnuti.
Nametnuto od: isAlwaysProtectedPath(path) → preskače requireLogin=false zaobilaženje
Zaobilaženje: Nema kada je requireLogin=false; JWT uvijek potreban
Ove rute su destruktivne ili nepovratne. Dozvoljavanje istih u instalaciji "bez lozinke" značilo bi da bi svako na istoj LAN mreži mogao obrisati bazu podataka ili ugasiti proces servera.
| Putanja | Razlog |
|---|---|
/api/shutdown |
Prekida proces servera |
/api/settings/database |
Izvoz, uvoz i brisanje baze podataka |
/api/db-backups |
Pristup arhivi potpune sigurnosne kopije baze podataka |
/api/settings/export-json |
Izvozi kompletan blob postavki (uključujući tajne) |
/api/settings/import-json |
Zamjenjuje kompletan blob postavki |
/api/providers/health-autopilot/actions |
Izvršava autopilot akcije sanacije |
/api/settings/obsidian |
Kreira višekratne WebDAV akreditive za bilo koji korijen trezora |
Odgovor na kršenje: 401 Authentication required
/api/settings/obsidian pokriva svoj /webdav podređeni: POST usmjerava WebDAV datotečnu uslugu —
koju poslužuje prilagođeni Node sloj prije Next.js-a, izvan ovog cjevovoda — na korijen koji odabere pozivatelj
i vraća svježe kreirane Basic akreditive, DELETE ih rotira, a roditeljski POST pohranjuje
Obsidian REST API token. GHSA-62vw je samo maskirao GET otkrivanje lozinke; izdavanje je
još uvijek bilo na nivou otvorenog kvara (GHSA-7pq4-8pvv-rx7r). enableObsidianVaultSync() dodatno
odbija trezor koji je, nalazi se unutar, ili sadrži direktorij podataka.
Bez konfigurirane administratorske lozinke (i bez INITIAL_PASSWORD), isAuthRequired() u
src/shared/utils/apiAuth.ts drži anonimni bootstrap otvoren samo za loopback peer-ove.
Loopback se određuje iz pouzdanih peer signala, redom: stvarni TCP peer sa tokenom
(PEER_IP_HEADER + VIA_PROXY_HEADER, što politika vidi), vlastita presuda cjevovoda
AUTHZ_HEADER_PEER_LOCALITY (što rukovatelji ruta vide, pouzdano samo dok je
OMNIROUTE_PEER_STAMP_TOKEN postavljen), ili stvarni socket peer za direktne pozivatelje. Host /
nextUrl.hostname se nikada ne konsultuju, a pisanje prve lozinke
(POST /api/settings/require-login) je pod istim ograničenjem, a ne otvoreno za svakog
mrežnog peer-a (GHSA-7pq4-8pvv-rx7r). managementPolicy eksplicitno prosljeđuje svoju vlastitu peerContext presudu,
tako da ORIGINALNI (prije uklanjanja) zaglavlja zahtjeva nikada ne odlučuju o tome.
Sve ostale rute za upravljanje. Autentifikacija je potrebna osim ako requireLogin=false nije
konfigurisan. CLI tokeni mogu autentifikovati ove rute (loopback + validan HMAC).
managementPolicy.evaluate(ctx)
1. isLocalOnlyPath(path)?
→ povratna petlja → nastavi dalje
→ nije povratna petlja, Bearer s opsegom manage
I isLocalOnlyBypassableByManageScope → dozvoli (management_key)
→ u suprotnom → odbij 403 LOCAL_ONLY
2. isInternalModelSyncRequest(ctx)?
→ dozvoli (system)
3. hasValidCliToken(headers)?
→ dozvoli (cli) [povratna petlja + HMAC provjera pomoću timingSafeEqual]
4. isAlwaysProtectedPath(path) ili requireLogin=true?
→ isDashboardSessionAuthenticated?
→ dozvoli (dashboard_session)
→ Bearer s opsegom manage na putanji koju nije moguće zaobići?
→ dozvoli (management_key)
→ odbij 401/403
5. requireLogin=false?
→ dozvoli (anonymous)
Grana s opsegom manage iz koraka 1 jedina je autentificirana putanja koja može zadovoljiti LOCAL_ONLY rutu; način otkaza autentifikacijskog pozadinskog sistema vraća 503 (ne 403), tako da istekla baza podataka ne dovede neprimjetno do prelaska na „odbij“.
- Dodajte prefiks putanje u
LOCAL_ONLY_API_PREFIXESusrc/server/authz/routeGuard.ts - Dodajte test u
tests/unit/authz/routeGuard.test.tskoji potvrđuje daisLocalOnlyPath()vraća true za novi prefiks - Nikada ne preskačite ovaj korak — pogledajte strogo pravilo br. 15 u
CLAUDE.md - Odlučite: pripada li ova ruta TAKOĐER u
LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES? Zadani odgovor je ne. Uključite je samo kada je rutu sigurno izložiti imaocu opsega manage (tj. NE pokreće proizvoljni kod kojim upravlja korisnik).
- Potvrdite da ruta ne izvršava kod ili naredbe koje je dostavio korisnik. Ako ih izvršava, zaustavite se — ovaj izuzetak nije odgovarajući alat.
- Dodajte prefiks u
LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXESusrc/server/authz/routeGuard.ts - Dodajte pokrivenost u
tests/unit/authz/management-policy.test.tsza sva četiri oblika zahtjeva: bez Bearer tokena (403), Bearer s opsegom manage (dozvoli), Bearer bez opsega manage (403) i regresijski test po prefiksu kojim se potvrđuje da/api/cli-tools/runtime/*ostaje strogo ograničen na povratnu petlju čak i uz Bearer s opsegom manage.
| Datoteka | Namjena |
|---|---|
src/server/authz/routeGuard.ts |
Konstante i pomoćne funkcije |
src/server/authz/policies/management.ts |
Logika evaluacije |
tests/unit/authz/routeGuard.test.ts |
Jedinični testovi pomoćnika nivoa |
tests/unit/authz/management-policy.test.ts |
Jedinični testovi za evaluate() |
Prilikom dodavanja nove rute u docs/openapi.yaml, primijenite odgovarajuće
proširenje dobavljača ako je ruta klasificirana u routeGuard.ts:
| Klasifikacija u routeGuard.ts | YAML anotacija | Provođenje |
|---|---|---|
LOCAL_ONLY_API_PREFIXES |
x-loopback-only: true |
Bezuslovno blokirano izvan povratne petlje |
ALWAYS_PROTECTED_API_PATHS |
x-always-protected: true |
Autentifikacija je obavezna čak i uz requireLogin=false |
| Interna admin/debug ruta | x-internal: true |
Zadano skriveno iz /dashboard/api-endpoints |
| Nijedna (javni / standardni pristup uz autentifikaciju) | (anotacija nije potrebna) | Standardni pristup kojim upravlja requireLogin |
Dvije skripte osiguravaju dosljednost između YAML anotacija i routeGuard.ts:
scripts/check/check-openapi-coverage.mjs— neuspješno se završava ako je pokrivenost < 99%scripts/check/check-openapi-security-tiers.mjs— neuspješno se završava ako anotacijex-loopback-onlyilix-always-protectedodstupaju od konstanti definiranih u vrijeme prevođenja
Obje skripte pokreću se u pre-commit kuki i u CI-ju.
Ako je x-always-protected ili x-loopback-only anotiran na ruti koja NIJE u
konstanti u routeGuard.ts, skripta za pokrivenost završava se neuspješno. Rješenje je uvijek uskladiti
YAML s onim što routeGuard.ts zaista provodi — a ne dodavati rute u routeGuard.ts
bez istovremene implementacije logike provođenja.
docs/security/CLI_TOKEN.md— token ID-a uređaja za CLIdocs/architecture/AUTHZ_GUIDE.md— kompletan proces autorizacijedocs/frameworks/MCP-SERVER.md— transporti i opsezi MCP servera