Socket.dev / supply-chain finding attestation (한국어)
§1 — MITM 루트 CA 설치 (77484.js)
섹션 제목: “§1 — MITM 루트 CA 설치 (77484.js)”소스 파일:
src/mitm/cert/install.ts— 공개installCert()/uninstallCert(), 플랫폼별installCertWindows/Mac/Linux.src/mitm/systemCommands.ts— 설치 경로에서 사용하는 공통execFile/spawn/ PowerShell 헬퍼.
트리거: 사용자가 /dashboard/cli-tools/mitm의 로컬 대시보드에서
“MITM 프록시 활성화”를 클릭합니다. 이 라우트는 루프백 전용입니다 —
CLAUDE.md의 엄격한 규칙 #17과
src/server/authz/routeGuard.ts::isLocalOnlyPath()를 참조하십시오. 터널을
통해 노출된 JWT로는 이 코드 경로를 트리거할 수 없습니다.
수행되는 권한 작업(플랫폼별):
| OS | 명령 |
|---|---|
| Windows | UAC를 통한 certutil -addstore Root <cert> |
| macOS | sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <cert> |
| Linux | sudo cp <cert> <distro-trust-dir> + sudo update-ca-certificates (Debian) / sudo update-ca-trust (RHEL/SUSE) |
| Linux+Firefox/Chromium | certutil -d sql:<profile>을 통한 프로필별 NSS DB 업데이트 |
이 명령들은 mitmproxy, Charles Proxy, Fiddler 및 Caddy에서 사용하는 것과
동일한 명령입니다. OmniRoute에 이러한 명령이 존재한다는 사실은
docs/security/STEALTH_GUIDE.md에 문서화되어 있습니다.
v3.8.6 완화 조치:
runElevatedPowerShell()은 더 이상-EncodedCommand <base64utf16le>을 사용하지 않습니다. 권한 상승 페이로드는 호출별 임시.ps1파일(모드 0o600, 비공개mkdtempSync디렉터리 내부)에 기록되고-File을 통해 참조됩니다. 이 파일은finally에서 링크 해제됩니다. 이를 통해 Socket.dev의 AI 분류기가 플래그한 전형적인 PowerShell을 통한 base64 권한 상승 핑거프린트를 제거합니다.installCertWindows에는 이 문서를 가리키는 인라인SECURITY-AUDITOR-NOTE:블록이 포함되어 있습니다.
유지하는 이유: MITM 프록시는 docs/security/STEALTH_GUIDE.md와
docs/frameworks/MITM-PROXY.md에서 사용하는 문서화된 기능입니다. 이를
제거하면 에이전트 브리지 기능 세트가 손상됩니다.
§2 — Zed 자격 증명 가져오기 (app/api/providers/zed/import/route.js)
섹션 제목: “§2 — Zed 자격 증명 가져오기 (app/api/providers/zed/import/route.js)”소스 파일:
src/app/api/providers/zed/discover/route.ts(v3.8.6에서 새로 추가됨)src/app/api/providers/zed/import/route.tssrc/lib/zed-oauth/keychain-reader.tssrc/lib/zed-oauth/credentialFingerprint.ts(v3.8.6에서 새로 추가됨)
트리거: 사용자가 로컬 대시보드의 Providers 페이지에서 “Import from Zed”를 클릭합니다. 엔드포인트는 requireManagementAuth로 보호됩니다. Zed 편집기 자체는 문서화된 서비스 이름을 사용하여 공급자 API 키를 OS 키체인에 기록합니다. 자세한 내용은 https://zed.dev/docs/ai/llm-providers 를 참조하세요.
v3.8.5 동작(Socket.dev가 플래그한 버전):
POST /import는 자격 증명을 검색하고 한 번의 요청으로 로컬 SQLite 저장소에 자동 저장했습니다. 계정별 확인이나 지문 없이 단순히 “N개의 토큰을 찾았으며 모두 가져왔습니다.“라고 처리했습니다.
v3.8.6 완화 조치 — 2단계 확인:
- **
POST /api/providers/zed/discover**는{ candidates: [{ provider, service, account, fingerprint }] }를 반환합니다. 원본 토큰은 절대 전송되지 않습니다. 지문은sha256(service|account|token).slice(0,16)입니다. - 대시보드는 후보 목록을 렌더링하고, 운영자는 가져올 항목을 선택한 다음
{ confirmedAccounts: [{ service, account, fingerprint }] }를 **POST /api/providers/zed/import**로 전송합니다. - 가져오기 엔드포인트는 서버에서 키체인을 다시 읽고
(service, account, fingerprint)를 기준으로 필터링합니다. 변조되거나 재전송된 검색 응답이 가져오기 엔드포인트를 속여 관련 없는 토큰을 저장하도록 할 수 없습니다. 검색 이후 실제 토큰이 변경되었다면 지문이 더 이상 일치하지 않으므로 해당 자격 증명을 건너뜁니다.
OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true 환경 변수 플래그는 아직 자동화를 업데이트하지 않은 운영자를 위해 v3.8.5 동작을 유지합니다. 이 플래그는 v3.9에서 제거될 예정입니다.
유지하는 이유: Zed 가져오기는 이미 Zed를 사용 중이며 공급자 키를 다시 붙여 넣지 않고 OmniRoute에 복제하려는 사용자를 위한 가장 편리한 온보딩 경로입니다.
§3 — execFile / spawn / 권한 상승 PowerShell (21843.js)
섹션 제목: “§3 — execFile / spawn / 권한 상승 PowerShell (21843.js)”소스 파일: src/mitm/systemCommands.ts.
플래그된 이유: 이 청크는 execFileWithPassword, runElevatedPowerShell 및 공유 quotePowerShell 헬퍼를 다시 내보냅니다. Socket.dev의 AI 분류기는 이를 범용 “호스트 실행 + 권한 상승 툴킷”으로 인식합니다. OmniRoute 내에서는 MITM 인증서 설치 경로(§1)와 sudo 명령 실행을 위한 execFileWithPassword에서만 사용됩니다.
v3.8.6 완화 조치:
runElevatedPowerShell리팩터링(§1 참조).runElevatedPowerShell과execFileWithPassword양쪽의 인라인SECURITY-AUDITOR-NOTE:블록은 허용 목록에 등록된 호출자와 고정된 실행 파일 목록을 문서화합니다.execFileWithPassword의spawn()호출에는 이 헬퍼가 전달받을 수 있도록 허용된 실행 파일 목록과 함께nosemgrep마커가 포함됩니다. 사용자 입력에서finalCommand/finalArgs로 이어지는 경로는 없습니다.
§4 / §6 — 9router 서비스 감독자 (api/services/9router/{start,restart}/route.js)
섹션 제목: “§4 / §6 — 9router 서비스 감독자 (api/services/9router/{start,restart}/route.js)”소스 파일:
src/app/api/services/9router/_lib.ts— 감독자 팩터리.src/app/api/services/9router/{start,stop,restart,status,install,update,auto-start}/route.ts.src/lib/services/ServiceSupervisor.ts— 범용 프로세스 생성 / 상태 폴링 / 로그 버퍼.
트리거: 사용자가 로컬 대시보드의 내장 서비스 페이지에서 “Install” / “Start”를 클릭합니다.
이미 적용된 보호 조치:
src/server/authz/routeGuard.ts에 따라 모든/api/services/*경로는 LOCAL_ONLY입니다(하드 규칙 #17). 루프백 적용은 모든 인증 검사보다 먼저 이루어지므로 유출된 JWT로도 해당 경로에 접근할 수 없습니다.- 9router DB 행은
status='not_installed', auto_start=0으로 시드됩니다(src/lib/db/migrations/071_services.sql:19참조). 서비스는 최초 실행 시 시작되지 않습니다. spawn()은src/lib/services/installers/ninerouter.ts의resolveSpawnArgs(apiKey, PORT)가 반환한 바이너리 경로로 호출되며, 이는 지원되는 바이너리의 고정된 허용 목록입니다.- Stdout/stderr는 메모리에 버퍼링됩니다(5 MB 제한,
_lib.ts참조). 사용자가 대시보드에서 로깅을 활성화하지 않는 한 디스크에는 기록되지 않습니다.
v3.8.6 완화 조치: 기능 변경은 없습니다. 최소 빌드 프로필
(OMNIROUTE_BUILD_PROFILE=minimal)은 권한이 필요한 경로를 번들에서 물리적으로 제거하려는 사용자를 위해
src/lib/services/installers/ninerouter.ts를 스텁으로 대체합니다.
유지하는 이유: 9router는 선택적으로 로컬에 설치할 수 있는 동반 서비스(WordPress 스타일 플러그인과 유사)이며, 엄격한 옵트인 방식입니다.
§5 — OmniRoute Cloud Sync 자격 증명 다시 쓰기 (api/keys/[id]/route.js)
섹션 제목: “§5 — OmniRoute Cloud Sync 자격 증명 다시 쓰기 (api/keys/[id]/route.js)”소스 파일:
src/lib/cloudSync.ts—syncToCloud()/updateLocalTokens().src/app/api/keys/[id]/route.ts—syncKeysToCloudIfEnabled()를 호출합니다.
트리거: isCloudEnabled()가 true를 반환하고(대시보드에서 설정)
CLOUD_URL도 구성된 경우입니다. 둘 다 비활성화된 경우에는 Cloud
엔드포인트로 외부 네트워크 호출이 이루어지지 않습니다.
v3.8.5 동작(Socket.dev가 정확히 포착한 버그):
updateLocalTokens()는 cloudUpdatedAt > localUpdatedAt일 때 Cloud 응답의
accessToken, refreshToken, providerSpecificData로 기존 값을
덮어썼습니다. HMAC도, 서명도, 체크섬도 없었습니다. 잘못 구성되었거나
악의적인 CLOUD_URL(또는 채널상의 MITM)이 공급자 OAuth 토큰을
은밀하게 바꿀 수 있었습니다.
v3.8.6 완화 조치:
- HMAC 검증:
verifyCloudSignature(rawBody, sigHeader)는 JSON을 파싱하기 전에X-Cloud-Sig헤더(HMAC-SHA256(OMNIROUTE_CLOUD_SYNC_SECRET, rawBody))를 확인합니다. 비밀 값이 설정되어 있으면 서명이 필수입니다. 설정되어 있지 않으면(레거시 모드) 경고를 기록하고 응답을 수락합니다. 단, v3.9부터는 비밀 값이 필수가 됩니다. - 비밀 필드 옵트인:
accessToken/refreshToken/providerSpecificData는OMNIROUTE_CLOUD_SYNC_SECRETS=true인 경우에만 덮어씁니다. 기본 모드에서는 자격 증명이 아닌 메타데이터(expiresAt,status,lastError*,rateLimitedUntil,updatedAt)만 동기화합니다. 이는 원격 토큰 동기화에 의존하던 사용자에게 호환성을 깨뜨리는 변경 사항이며, 해당 사용자는 명시적으로 옵트인해야 합니다.
이 기능을 유지하는 이유: Cloud Sync는 OmniRoute Cloud 테넌트가 팀 자격 증명을 중앙에서 관리할 수 있는 유일한 방법입니다. 이 수정으로 위협 모델이 다음과 같이 명확해집니다. “서버는 서명하고, 클라이언트는 검증하며, 운영자는 옵트인한다.”
빌드 프로필: minimal
섹션 제목: “빌드 프로필: minimal”Socket 친화적인 아티팩트가 필요한 사용자는 다음과 같이 빌드하십시오.
OMNIROUTE_BUILD_PROFILE=minimal npm run buildwebpack NormalModuleReplacementPlugin은 네 개의 모듈을 스텁에
별칭으로 연결합니다.
| 모듈 | 스텁 |
|---|---|
src/mitm/cert/install.ts |
src/mitm/cert/install.stub.ts |
src/lib/zed-oauth/keychain-reader.ts |
src/lib/zed-oauth/keychain-reader.stub.ts |
src/lib/cloudSync.ts |
src/lib/cloudSync.stub.ts |
src/lib/services/installers/ninerouter.ts |
src/lib/services/installers/ninerouter.stub.ts |
각 스텁은 동일한 인터페이스를 내보내지만, 모든 함수는 런타임에
featureDisabledError(name)를 발생시킵니다. 비활성화된 모듈에 의존하는
라우트는 민감한 코드 경로를 활성화하는 대신 명확한 메시지와 함께 HTTP
503을 반환합니다.
생성된 번들은 omniroute-secure로 게시하기 위한 것입니다. 게시 절차는
docs/ops/PUBLISHING_SECURE.md를 참조하십시오.
플러그인 분리(v4에서 추적)
섹션 제목: “플러그인 분리(v4에서 추적)”장기적으로는 npm package를 개별적으로 감사할 수 있는 모듈로 분리할 계획입니다. 관련 추적 이슈는 GitHub 이슈 트래커의 v4 마일스톤을 참조하세요.
HagiCode
HagiCode는 구조화된 워크플로, 다중 에이전트 실행, Hero Dungeon 뷰를 갖춘 에이전트 코딩 작업 공간입니다.
더 스마트하고 빠르며 즐거운 에이전트 워크플로로 유용한 소프트웨어를 만드세요.

- Smart구조화된 워크플로는 의도를 아이디어부터 배포까지 실행 가능한 경로로 바꿉니다.
- Efficient다중 에이전트 워크플로로 조사, 구현, 검토를 병렬로 진행합니다.
- FunHero Dungeon은 긴 코딩 세션을 시각적이고 협업적인 경험으로 만듭니다.