보안

기기를 떠나기 전에 암호화돼요

내 노트는 내 기기에서 암호화되고, 그 키는 나와 내가 연결한 에이전트만 열 수 있어요. 키가 어떻게 작동하는지, 저희 서버가 무엇을 볼 수 있고 없는지, 데이터가 어디에 저장되는지, 그리고 아직 풀지 못한 한계까지 여기에 정리했어요.

키

비밀번호는 절대 내 기기를 떠나지 않아요.

가입하면 브라우저가 내 키를 만들어요. 비밀번호는 Argon2id(64 MiB 메모리에서 최소 3회 반복)로 내 기기에서 마스터 키가 돼요. 마스터 키에서 두 가지 값이 나와요. 하나는 로그인 해시로, 로그인할 때 저희가 받는 건 이것뿐이에요(저희는 그 해시만 저장해요). 다른 하나는 내 계정 키를 여는 키예요.

워크스페이스마다 고유한 무작위 키가 있고, 그 안의 모든 것은 이 키로 XChaCha20-Poly1305 암호화돼요. 나와 내가 연결한 각 에이전트는 이 키의 사본을 받아요. 사본은 받는 쪽 자신의 키 쌍으로 봉인되고 내가 서명하기 때문에, 저희 서버가 자기 키를 몰래 끼워 넣을 수 없어요. 모두 libsodium 위에 만들었고, 직접 만든 암호 기본 요소는 쓰지 않아요.

내 기기에서

비밀번호Argon2id

내 기기에서 마스터 키가 돼요. 둘 다 저희에게 절대 보내지지 않아요.

복구 키

무작위 32바이트로, 만들 때 한 번만 보여 줘요. 비밀번호를 잊었을 때 써요. 저희에게 절대 보내지지 않아요.

각각 잠긴 사본을 열어요

계정 키X25519Ed25519

가입할 때 브라우저에서 만들어져요. 키 쌍 하나는 워크스페이스 키를 열고, 다른 하나는 내 변경에 서명해요.

자기 몫의 봉인된 사본을 열어요

워크스페이스 키XChaCha20-Poly1305

워크스페이스마다 무작위 키 하나. 에이전트를 해제하면 그 뒤에 쓰는 내용은 새 키를 써요.

자기 몫의 사본

연결된 에이전트는 워크스페이스 키의 자기 몫 사본을 가져요

에이전트 키X25519Ed25519

연결하는 컴퓨터에서 knowtarium CLI가 만들어요. 하나는 자기 몫으로 봉인된 워크스페이스 키 사본을 열고, 다른 하나는 내가 보증하면 변경에 서명해요.

그 안의 모든 것을 암호화해요

노트 텍스트, 제목, 파일 이름, 속성, 태그, 링크, 폴더와 워크스페이스 이름, 댓글, 기록, 첨부 파일

내 콘텐츠는 암호화된 상태로만 나가요

저희 서버에는

  • 암호화된 내 노트, 이름, 댓글, 첨부 파일
  • 비밀번호로 잠기고, 복구 키로 한 번 더 잠긴 내 계정 키
  • 내가 서명한, 워크스페이스 키의 봉인된 사본들
  • 공개 키와 서명
  • 비밀번호와 복구 키를 확인하는 단방향 해시

이 중 어느 것도 내 기기에만 있는 키 없이는 노트를 열 수 없어요.

키가 맞물리는 방식: 비밀번호와 복구 키는 각각 계정 키를 열고, 계정 키는 워크스페이스 키를 열어요. 연결된 각 에이전트는 자기 키로 자기 몫의 사본을 열고, 워크스페이스 키는 워크스페이스 안의 모든 것을 암호화해요. 저희 서버는 내 키 중에서 잠긴 사본, 공개 키, 서명, 단방향 해시만 저장하고, 내 콘텐츠는 암호문으로만 받아요.

저희가 볼 수 있는 것

저희 서버에 닿는 것.

저희가 볼 수 있는 것저희가 절대 볼 수 없는 것
계정

저희가 볼 수 있는 것

  • 이메일 주소, 그리고 인증했는지 여부
  • 비밀번호와 복구 키를 확인하는 단방향 해시 (비밀번호나 키 자체는 아니에요)
  • 공개 키, 비밀번호의 키 설정(솔트와 강도), 그리고 저희가 열 수 없게 잠긴 개인 키
  • 세션: 각 세션이 언제 시작됐고, 마지막으로 활동했고, 끝나는지, 그리고 브라우저의 user-agent (IP 주소는 없어요)
  • 계정이 마지막으로 활동한 시점
  • 색상 테마 같은 앱 설정

저희가 절대 볼 수 없는 것

  • 비밀번호, 그리고 비밀번호로 만든 마스터 키
  • 복구 키
  • 잠기지 않은 개인 키
결제

저희가 볼 수 있는 것

  • 요금제, 구독 상태, 결제 내역(금액, 통화, 날짜)
  • Polar의 고객 ID

저희가 절대 볼 수 없는 것

  • 카드 정보: 결제는 Polar가 자체 페이지에서 받아요
노트

저희가 볼 수 있는 것

  • 사용 중인 저장 공간, 그리고 암호화된 항목 각각의 크기
  • 버전 번호, 타임스탬프, 그리고 각 항목이 쓰는 워크스페이스 키의 세대
  • 개수: 버전, 댓글, 확인, 대기 중인 변경, 첨부 파일 조각
  • 각 워크스페이스가 기록을 보관하는 기간

저희가 절대 볼 수 없는 것

  • 노트 텍스트, 제목, 파일 이름
  • 속성, 태그, 링크
  • 첨부 파일과 그 이름, 유형
  • 댓글과 기록의 세부 내용
  • 버전 사이에 무엇이 바뀌었는지
워크스페이스와 폴더

저희가 볼 수 있는 것

  • 워크스페이스, 폴더, 노트, 첨부 파일의 ID와 중첩 구조
  • 폴더의 모든 변경(누가, 언제, 어디로 옮겼는지, ID로)과 변경 전후의 이름 (이름은 암호화돼요)
  • 어떤 폴더가 워크스페이스의 루트인지 (ID로)

저희가 절대 볼 수 없는 것

  • 워크스페이스와 폴더의 이름
에이전트

저희가 볼 수 있는 것

  • 각 변경을 어떤 사람이나 연결된 에이전트가 했는지, 그리고 어떤 종류였는지(편집, 삭제, 승인) (ID로, 서명된 변경에는 서명과 함께)
  • 각 에이전트나 브라우저가 어떤 노트를 언제 가져가는지 (ID로, 요청이 들어올 때 보여요. 동기화 API는 이를 기록하지 않아요)
  • 각 에이전트의 확인이 적용됐는지 거부됐는지
  • 각 에이전트의 접근 범위(읽기 또는 읽기·쓰기, 어떤 폴더인지 ID로), 권한과 내가 서명한 모든 권한 변경, 공개 키, 그리고 연결, 마지막 사용, 해제 시점
  • 어떤 폴더가 먼저 묻도록 설정됐는지 (ID로), 그리고 그 설정을 언제 바꿨는지
  • 어떤 노트가 에이전트용 지침인지 (내가 서명한 목록에서 ID로), 그리고 나나 수락된 변경이 언제 그것을 업데이트했는지

저희가 절대 볼 수 없는 것

  • 에이전트의 이름
  • 에이전트가 읽거나, 쓰거나, 제안한 내용
  • 에이전트용 지침의 내용
  • 에이전트의 확인이 무엇을 찾았는지, 어떤 노트를 비교했는지
웹 클리퍼

저희가 볼 수 있는 것

  • 각 워크스페이스의 인박스가 어떤 폴더인지 (ID로), 그리고 내 서명이 있는 인박스의 공개 키
  • 연결한 확장 프로그램마다: 접근 토큰의 해시, 내 서명이 있는 서명용 공개 키, 저장할 워크스페이스(ID로), 그리고 연결, 마지막 사용, 마지막 페이지 저장, 연결 해제 시점
  • 대기열에서 기다리는 페이지마다: 암호화된 크기, 도착 시점, 보낸 확장 프로그램. 노트로 정리되면 대기열에서 삭제돼요

저희가 절대 볼 수 없는 것

  • 저장한 각 페이지의 링크, 제목, 메모, 카테고리
  • 확장 프로그램의 이름
네트워크와 검색

저희가 볼 수 있는 것

  • IP 주소는 요청할 때마다 저희 서버에 닿아요. 동기화 API는 이를 기록하지 않고(요청 제한에는 키가 있는 해시만 남아요), 웹 앱을 제공하는 Vercel은 서버 로그에 잠깐 보관해요

저희가 절대 볼 수 없는 것

  • 검색과 그래프: 둘 다 내 기기에서 만들어져요

두 곳의 제공자는 조금 더 봐요. Polar가 저희에게 보내는 알림에는 이름과 청구지 주소도 들어 있어요. 저희는 이를 저장하지 않지만 Polar 대시보드에서 볼 수 있어요. 계정 이메일을 보내는 Resend는 이메일 주소와 각 이메일의 내용을 받아요.

웹 클리퍼 브라우저 확장 프로그램은 내 노트를 읽는 키를 갖고 있지 않아요. 저장하는 각 페이지는 브라우저에서 암호화돼요. 개인정보 처리방침에 무엇을 읽고 저희가 무엇을 저장하는지 나와 있어요.

개인정보 처리방침에도 같은 데이터가 왜, 얼마나 오래 보관되는지와 함께 나와 있어요.

저장 위치

EU에 저장돼요.

동기화 API의 데이터베이스, 스토리지 버킷, 워크스페이스 객체는 Cloudflare의 EU 관할 구역에 보관돼요. 데이터베이스와 버킷은 그곳에서 만들어졌고, 모든 워크스페이스는 그곳에서 만든 Durable Object 안에 있어요. 배포 검사는 워크스페이스나 버킷을 다른 곳에 두는 설정을 거부해요. 오류와 Polar의 비정상적인 결제 알림에 대한 짧은 로그(무슨 일이 코드 어디에서 일어났는지, Cloudflare의 요청 ID나 Polar의 알림 ID 같은 기술 ID. IP 주소나 내 콘텐츠는 절대 없어요)는 Cloudflare의 로그 기능이 보관하는데, 이 부분은 그 설정의 적용을 받지 않아요.

여기까지는 데이터가 저장되는 곳에 관한 이야기예요. 미국 회사인 Cloudflare가 처리자로서 저희의 동기화 API를 운영해요. 이 웹사이트와 웹 앱은 Vercel이 제공하고, 계정 이메일은 Resend가 보내고, 유료 요금제는 Polar가 판매 대행자(merchant of record)로 판매해요. 내 노트는 이들에게 닿더라도 암호화된 상태로만 닿아요. 각각 무엇을 받는지는 개인정보 처리방침에 나와 있어요.

  • EU 관할 구역

    D1 데이터베이스

    계정, 잠긴 형태의 키, 연결된 에이전트와 브라우저 확장 프로그램, 결제 상태.

  • EU 관할 구역

    R2 버킷

    노트의 암호화된 버전, 에이전트가 제안한 변경, 첨부 파일.

  • EU 관할 구역

    Durable Objects

    워크스페이스마다 하나: 폴더, 버전, 댓글, 기록, 그리고 웹 클리퍼에서 온 대기 중인 페이지. 모두 ID로, 암호화된 채로.

에이전트

에이전트는 내 컴퓨터에서 복호화해요.

  • 01

    내 컴퓨터에서 복호화

    로 연결하거나 에이전트에게 연결해 달라고 하면, 내 컴퓨터에 에이전트 자신의 키가 만들어지고 그 키로 봉인된 워크스페이스 키 사본을 받아요. 에이전트가 실행하는 MCP 서버가 그곳에서 노트를 복호화해요. 내 노트는 암호문으로만 저희 서버를 거쳐 가요.

  • 02

    내가 보증해요

    에이전트를 승인하면 그 키에 내가 서명해요. 에이전트가 저장하는 각 변경은 그 키로 서명되고, 에이전트의 것으로 표시되며, 클릭 한 번으로 되돌릴 수 있어요. Ask me first로 설정한 폴더에서는 변경이 대신 나를 기다려요. 삭제나 재정리는 내가 준 권한으로만 하고, 그 권한마다 내가 서명해요.

  • 03

    AI 제공자는 에이전트가 읽은 내용을 봐요

    에이전트가 읽은 내용은 그 제공자의 약관에 따라 AI 제공자(예: Anthropic이나 OpenAI)에게 가요. 저희는 AI 모델을 실행하지 않으니, 저희 쪽에서 모델로 보내는 건 없어요.

  • 04

    언제든 해제할 수 있어요

    에이전트를 해제하면 바로 저희 서버에서 차단되고, 그 뒤에 쓰는 내용은 에이전트가 갖지 않은 새 워크스페이스 키를 써요. 에이전트는 이미 읽은 내용과 이전 키는 그대로 갖고 있어요.

원격 커넥터는 아직 없어요. claude.ai와 ChatGPT용 커넥터는 증명된 엔클레이브에서 실행할 계획이에요. 브라우저가 키를 넘기기 전에 코드를 확인하는 봉인된 서버예요. 지금은 하나도 없으니, 내 노트를 복호화하는 Knowtarium 서버는 없어요.

알려진 한계

암호화로 해결할 수 없는 것.

웹 앱 코드는 저희가 제공해요

웹 앱을 열 때마다 브라우저는 노트를 암호화하는 코드를 저희에게서 불러와요(Vercel에서 호스팅해요). 저희 쪽이나 호스트 쪽에서 그 코드가 변조되면 내 키가 유출될 수 있고, 쉽게 알아차리기 어려워요. 엄격한 Content Security Policy가 앱이 자기 스크립트만 실행하고 자기 자신과 동기화 API(그리고 에이전트를 연결하는 동안 내 컴퓨터의 CLI)하고만 통신하게 해서 주입된 스크립트를 막지만, 잘못된 배포로부터는 지켜 줄 수 없어요. 브라우저가 실행하는 코드를 확인할 방법은 아직 없어요.

둘 다 잃어버리면 끝이에요

비밀번호와 복구 키를 둘 다 잃어버리면 저희도, 나도 노트를 복호화할 수 없어요(이미 연결해 둔 에이전트만 처음부터 다시 시작하기 전까지 읽을 수 있어요). 같은 이메일로 다시 시작할 수 있지만, 그러면 계정의 모든 워크스페이스가 삭제돼요.

숨길 수 없는 메타데이터

이메일, 크기, 타임스탬프, 개수, 폴더와 노트의 중첩 구조, 어떤 노트를 언제 가져갔는지, 어떤 에이전트가 무엇을 바꿨는지. 저희 서버에 접근할 수 있는 사람은 내가 언제, 얼마나 일하는지는 알 수 있지만, 무엇을 썼는지는 절대 알 수 없어요.

해제된 에이전트는 이전 키를 갖고 있어요

새 키는 해제 이후에 쓴 내용만 보호해요. 다시 암호화되는 건 없어요. 그 전에 쓴 내용은 이전 키로 남아 있어요. 노트는 바뀌고 이전 버전의 기록 보관 기간이 지날 때까지, 댓글, 기록, 첨부 파일은 보관되는 동안 계속요. 해제된 에이전트가 이 암호화된 사본을 손에 넣으면 여전히 읽을 수 있지만, 저희 서버는 더 이상 이를 주지 않아요.

폴더와 권한은 저희 서버가 강제해요

일부 폴더로 제한했거나 삭제를 허락하지 않은 에이전트도 워크스페이스 키는 갖고 있어요. 다른 폴더를 막고 허락하지 않은 일을 거부하는 건 저희 서버예요. 에이전트는 첨부 파일을 절대 삭제하지 않고, 모든 삭제, 이동, 폴더 변경에는 에이전트의 서명이 남아요. 앱은 이를 내가 서명한 권한과 대조하고, 2주 동안(기록 보관 기간이 더 짧다면 그 기간 동안) Undo와 함께 목록에 보여 줘요(삭제한 노트는 기록 보관 기간 안이라면 다시 살릴 수 있어요). 에이전트의 규칙은 내가 요청할 때만 삭제하거나 재정리하라고 알려 주지만, 그건 잠금이 아니라 지시예요. 어떤 일이 있어도 에이전트가 닿으면 안 되는 폴더는 다른 워크스페이스에 두세요.

지침은 안내일 뿐, 강제하지 않아요

폴더 지침은 에이전트에게 어떻게 쓸지 알려 주지만, 모델이 잘못 따를 수도 있고, 수정된 클라이언트는 건너뛸 수도 있어요. 저희가 강제하는 건 누가 지침을 바꾸느냐예요. 저희 서버는 에이전트가 지침에 직접 쓰는 것을 거부하고, 에이전트는 내가 서명한 지침만 적용해요. 일부 폴더로 제한된 에이전트도 그 위 폴더의 지침은 읽으니, 그곳에는 에이전트가 보면 안 되는 내용을 두지 마세요.

오픈 소스

코드를 읽어 보세요.

암호화, 키 처리, 동기화 클라이언트, CLI, MCP 서버는 MIT 라이선스의 오픈 소스로 knowtarium-sdk에 있어요. 웹 앱도 같은 패키지 위에 만들어졌어요. 0.1.0 이후 CLI의 모든 릴리스는 그 저장소에서 provenance와 함께 npm에 게시되기 때문에, 어떤 빌드가 만들었는지 npm에 기록돼요.

아직 독립적인 보안 감사는 받지 않았어요. 문제를 발견하면 제목에 “Security”를 넣어 support@knowtarium.com으로 이메일을 보내 비공개로 알려 주세요.