이번 작업에서 가장 크게 남은 보안 교훈은 저장 방식에 관한 것이 아니었습니다. 권한에 관한 것이었습니다. 민감한 데이터를 원격 시스템으로 보내지 않는 것은 중요하지만, 누가 정보를 요청할 수 있는지, 무엇을 받을 수 있는지, 권한이 언제 끝나는지, 요청이 실패하면 어떻게 되는지까지 답해주지는 않습니다.

Luthn을 개발하면서 이 차이를 더 이상 무시하기 어려워졌습니다. 연결은 에이전트가 서비스에 도달할 수 있게 해줄 뿐입니다. 그 사실만으로 연결된 기록 전체를 읽어도 된다는 뜻은 아닙니다. 두 가지를 하나로 취급하면 편리한 연동이 조용히 넓은 접근 권한으로 바뀝니다.

경계는 데이터 흐름을 나누는 결정입니다

이제 저는 권한을 하나의 스위치가 아니라 서로 다른 판단의 연속으로 설명합니다.

단계 다음으로 넘어갈 수 있는 것 경계 뒤에 남는 것
턴 수집 제한된 최종 응답 capsule 원문 프롬프트·transcript·로컬 경로·비공개 원본
분류 redaction과 정책 검사를 거친 후보 민감하거나 분류되지 않은 내용
에이전트 읽기 공개 가능하고 만료되지 않은 safe projection 원본 Vault/source와 비공개 projection
보호 정보 접근 명시적 승인 뒤 요청자에게만 주는 제한된 결과 자격증명·키·제한 없는 원문 읽기
외부 발행 별도 승인을 받은 public projection 에이전트가 읽을 수 있었다는 사실 자체

한 사람이 작은 검문대에 요청 카드를 넣고, 큰 보관함은 닫힌 채 시간 제한이 있는 티켓만 나오는 모습

접근의 결과는 제한된 정보여야지, 연결 자체가 마스터키가 되어서는 안 됩니다.

이것은 NIST의 제로 트러스트 아키텍처와 OWASP의 authorization 지침이 공유하는 원칙을 실제 흐름으로 옮긴 것입니다. 인증과 인가는 다른 판단이고, 최소 권한은 한 번 정하고 끝나는 옵션이 아닙니다. “이 서비스가 연결될 수 있는가?”보다 먼저 “지금 이 요청에 필요한 가장 좁은 권한은 무엇인가?”를 물어야 합니다.

Luthn 구현에서 구체적으로 나눈 경계

Luthn 공개 문서는 제한된 memory loop를 설명합니다. 신뢰된 Stop hook이 턴이 끝난 뒤 제한된 capsule을 제출하면, Luthn이 에이전트에 보이기 전에 redaction과 분류를 적용합니다. 자동 recall은 새 작업의 시작점에서 최대 3개 항목, 약 600토큰, 200밀리초 fail-open 제한, 10분 cache를 사용합니다. 개인 저장소를 실시간 창처럼 열어두지 않고, 작업에 필요한 작은 맥락만 가져오려는 설계입니다.

보호 정보는 전혀 다른 경로를 탑니다. 요청에는 목적·세션·만료가 들어가고, 운영자는 제한된 detail projection을 확인한 뒤 명시적인 이유와 함께 승인하거나 거절합니다. 승인 뒤에도 일회성 capability는 요청자만 사용할 수 있고, 정해진 시간과 읽기 횟수 안에서만 결과를 반환합니다. 공개 문서의 기본값은 최대 60분과 1~3회 읽기입니다. 자격증명·access key·private key는 계속 차단됩니다.

승인 관문을 사이에 둔 두 요청 경로와 짧은 일회성 읽기, 보호 값을 담지 않는 메타데이터 감사 기록을 표현한 일러스트

보호 정보 읽기는 요청자에게 묶인 임시 결정이고, 감사 기록에는 보호 원문이 필요하지 않습니다.

이 분리가 중요한 이유는 에이전트에게 보이는 것과 외부에 발행할 수 있는 것이 같지 않기 때문입니다. safe summary가 작업에 도움을 주더라도 곧바로 공개 글의 재료가 되는 것은 아닙니다. Luthn은 외부 발행도 별도의 명시적 결정으로 다룹니다.

실패할 때도 경계가 남아야 합니다

경계는 공격이 아니라 일상적인 실패를 만났을 때도 작동해야 합니다. 승인을 확인할 수 없으면 추측해서 통과시키면 안 됩니다. 원격 memory service가 잠시 unavailable하더라도 로컬 개발까지 멈춰서는 안 됩니다. Luthn은 호스트 작업을 위해 hook 전달을 fail-open으로 두지만, 그렇다고 에이전트가 보호 원문을 읽는 경로를 열어주지는 않습니다. timeout은 공개 권한이 아닙니다.

만료도 같은 원칙으로 처리해야 합니다. 분류 중 요청이 만료됐다면 classifier가 늦게 끝났다는 이유로 승인으로 바뀌어서는 안 됩니다. 유효한 결정이 없는 결과 조회는 metadata-only로 남아야 합니다. 요청자 handle을 잃어버렸다면 권한을 넓히는 대신 새 요청을 만들어야 합니다.

metadata도 가볍게 볼 수 없습니다. 본문을 빼도 제목·tag·source label·audit event가 비공개 기록의 윤곽을 드러낼 수 있습니다. 그래서 Luthn의 audit trail은 결정을 설명할 수 있을 만큼만 남기고, 또 하나의 content store가 되지 않도록 설계합니다.

테스트가 경계를 실제 문장으로 만듭니다

“owner isolation이 켜져 있다”고 쓰는 것보다 다른 owner가 실제로 무엇을 받는지 묻는 테스트가 더 유용합니다. 공개 테스트에는 다음과 같은 검증이 들어 있습니다.

  • 인증된 identity로 개인 workspace를 만들고, 다른 owner의 memory가 read와 search에 나타나지 않는지 확인합니다.
  • 같은 shared workspace의 두 에이전트는 public-safe projection을 읽을 수 있지만 provenance는 각 범위 밖에 남는지 확인합니다.
  • 승인된 protected result는 요청 principal에게만 반환하고, 다른 agent에는 content를 주지 않으며 no-store header를 유지하는지 확인합니다.
  • classification 중 요청이 만료되면 승인을 거부하고 metadata-only expiry event를 남기는지 확인합니다.

이 테스트가 시스템이 공격에 절대 뚫리지 않는다는 뜻은 아닙니다. 대신 더 좁고 중요한 사실을 증명합니다. 의도한 경계를 실행 가능한 계약으로 만들었고, 나중에 경계를 약하게 바꾸면 반복 가능한 실패로 발견할 수 있다는 사실입니다.

다음 자동화에서 먼저 물을 질문

앞으로 자동화를 추가할 때는 “이 시스템이 데이터에 연결할 수 있는가?”로 시작하지 않으려 합니다. “지금 이 순간 어떤 권한이 존재해야 하는가?”를 먼저 묻겠습니다. 그 답에는 owner, 목적, 제한된 결과, 만료 규칙, 그리고 더 많이가 아니라 더 적게 반환하는 실패 경로가 들어 있어야 합니다.

넓은 연결을 바로 건네는 것보다 느린 설계입니다. 대신 설명하고, 테스트하고, 철회하고, 신뢰하기가 쉽습니다. 민감한 AI 시스템에서는 데모가 끝난 뒤에도 남아 있어야 할 보안이 바로 이런 모습에 가깝습니다.