
NocoDB 공유 베이스 링크가 실제 베이스 구성원을 초대할 수 있으며 공유 취소 후에도 유지됩니다.
NocoDB 공유 베이스 링크가 실제 베이스 멤버를 초대할 수 있고 공유 취소 후에도 유지될 수 있음
NocoDB를 검토하던 중 이 문제를 발견했으며, 간단한 보안 질문을 염두에 두었습니다:
공유 베이스 링크가 일시적인 공유 접근에서 실제 인증된 베이스 멤버십으로 경계를 넘을 수 있는가?
이 경우, 답은 '예'였습니다.
xc-shared-base-id로만 인증된 공유 베이스 세션은 ACL 목적상 일반 베이스 뷰어로 취급되었습니다. 뷰어 권한이 여전히 멤버 관리 엔드포인트에 도달할 수 있었기 때문에, 공유 베이스 UUID만 가진 사용자가 기존 베이스 멤버를 열거하고 임의의 이메일 주소를 베이스에 실제 멤버로 초대할 수 있었습니다.
초대된 사용자는 일반 가입 흐름을 통해 초대를 수락하고, 표준 인증된 계정을 얻은 후, 소유자가 공유 베이스 링크를 비활성화해도 베이스 접근 권한을 유지할 수 있었습니다.
이 문제는 CVE-2026-46552가 되었습니다.
프로젝트: NocoDB
확인된 영향을 받는 버전: 0.301.3
이는 NocoDB에 영향을 미쳤으며, 공식 사이트에서 NocoDB는 35,000개 이상의 조직이 신뢰하고 2천만 회 이상 다운로드된 것으로 소개됩니다. 또한 사이트는 Accenture, Western Digital, Hyundai, Walmart, PwC, Bosch, American Express와 같은 기업을 나열합니다.
공개 공유 베이스 링크 -> xc-shared-base-id가 일반 베이스 뷰어로 처리됨 -> 뷰어 ACL이 멤버 관리 엔드포인트에 도달함 -> 공격자가 베이스 사용자를 나열하고 임의 이메일 초대 -> 초대된 사용자가 일반 가입 토큰 수락 -> 공유 링크 취소 후에도 지속되는 인증된 베이스 접근 유지
NocoDB는 데이터베이스 기반 협업 플랫폼으로, 브라우저 기반 베이스 접근, 공유, 메타데이터 관리 및 사용자 멤버십 워크플로우를 노출합니다.
즉, 공유 모델은 실제 보안 경계입니다.
여기서 중요한 질문은 공유 베이스 링크가 공유 콘텐츠를 읽을 수 있는지 여부가 아니었습니다.
진짜 질문은:
공개 공유 주체가 인증된 베이스 멤버에게만 속해야 하는 작업을 수행할 수 있는가?
이 경우, 가능했습니다.
공개 공유 기능은 과소평가되기 쉽습니다.
그것은 실수입니다.
애플리케이션이 다음을 지원하면:
주된 위험은 단순한 데이터 노출만이 아닙니다.
더 강력한 위험은 경계 붕괴(boundary collapse) 입니다:
그것이 여기서 실제 문제였습니다.
로그인 검증의 버그가 아니었습니다. 토큰 위조 문제도 아니었습니다. 비밀번호 재설정 결함도 아니었습니다.
이는 고전적인 권한 부여 경계 실패(authorization boundary failure) 였습니다:
무작위로 엔드포인트를 찔러보고 흥미로운 응답을 기대하는 방식으로 접근하지 않았습니다.
더 강력한 경로는 먼저 가장 가치 있는 신뢰 경계를 식별하는 것이었습니다.
NocoDB의 경우, 그것은 다음 사이의 경계였습니다:
이 두 상태는 서로 교환 가능해서는 안 됩니다.
공유 베이스 링크는 범위가 지정되고, 취소 가능하며, 링크 기반 접근을 제공해야 합니다. 베이스 내에서 새로운 장기 주체를 생성할 수 없어야 합니다.
이것이 바로 여기서 실패한 경계입니다.
취약점은 공유 베이스 접근이 일반 ACL 경로에 통합된 방식에서 발생했습니다.
공유 베이스 프론트엔드 흐름에서 xc-shared-base-id가 주입되는 동안 일반 인증 헤더는 제거되었습니다.
그런 다음 백엔드에서 BaseViewStrategy가 xc-shared-base-id를 수락하고 공유 링크를 공유 베이스 구성에서 파생된 일반 roles / base_roles로 직접 변환했습니다.
그것이 첫 번째 문제였습니다.
두 번째 문제는 뷰어 수준 권한에 여전히 멤버 관리 작업이 포함되어 있다는 점이었습니다.
ACL 계층에서 ProjectRoles.VIEWER는 다음에 도달할 수 있었습니다:
baseUserListuserInvite이러한 권한은 일반 메타 경로를 보호했습니다:
GET /api/v2/meta/bases/:baseId/usersPOST /api/v2/meta/bases/:baseId/users따라서 공개 공유 세션이 실제 베이스 참가자를 대상으로 한 멤버십 엔드포인트에 효과적으로 접근할 수 있었습니다.
마지막 단계는 초대 흐름 자체에 있었습니다.
BaseUsersService.userInvite()는 역할 권한을 확인한 후 다음을 생성했습니다:
invite_token이 있는 실제 사용자 행그리고 공유 베이스 세션의 경우:
invited_by가 null이 됨요청 뒤에 실제 인증된 초대자 신원이 없었기 때문입니다.
이것이 전체 버그 체인입니다.
공유 베이스 링크를 소유하는 것만으로 충분했기 때문입니다.
공격자에게는 다음이 필요하지 않았습니다:
xc-auth악용 체인은 간단했습니다:
이는 취소 가능한 링크 공유를 지속적인 멤버십으로 전환합니다.
중요한 차별점은 취소 후에도 지속된다는 점입니다.
이것은 단순히:
"뷰어가 뷰어 엔드포인트를 호출할 수 있었다"
가 아닙니다.
취약한 주체는 일반 인증된 뷰어가 아니었습니다.
공개 공유 세션이었습니다.
애플리케이션이 일시적이고 링크 범위의 주체를 신뢰할 수 있다고 간주하여 다음을 수행하도록 허용했기 때문입니다:
진짜 질문은:
"공유 사용자가 공유 데이터를 읽을 수 있는가?"
가 아니었습니다.
진짜 질문은:
"공개 공유 접근이 공유 취소 후에도 지속되는 영구적인 인증된 접근으로 전환될 수 있는가?"
였습니다.
답은 '예'였습니다.
이것이 단순한 놀라운 애플리케이션 동작이 아닌 실제 권한 부여 취약점인 이유입니다.
로컬에서 다음에 대해 검증했습니다:
0.301.3dac49b0122c5ee655fb8f46a1b6e42dfeec1f3adhttp://127.0.0.1:8080재현은 간단했습니다.
먼저 일반 소유자 계정으로 로그인하여 새 베이스를 만들고, 테이블을 만든 후 공유 베이스 접근을 viewer로 활성화했습니다:
PATCH /api/v2/meta/bases/<baseId>/shared
Content-Type: application/json
{
"roles": "viewer"
}
그러면 공유 베이스 UUID가 반환되었습니다.
그런 다음 xc-auth를 전혀 보내지 않고 다음만 사용했습니다:
xc-shared-base-id: <sharedBaseUuid>
해당 헤더만 사용하여 다음을 호출했습니다:
GET /api/v2/meta/bases/<baseId>/users
200 OK가 반환되었고 이메일 주소를 포함한 실제 베이스 멤버가 노출되었습니다.
계속해서 xc-shared-base-id만 사용하여 다음을 호출했습니다:
POST /api/v2/meta/bases/<baseId>/users
Content-Type: application/json
{
"email": "[email protected]",
"roles": "viewer"
}
이 또한 200 OK를 반환했습니다.
이메일 전달 없이 로컬 랩 검증을 위해 SQLite 메타 데이터베이스에서 다음을 직접 확인했습니다:
nc_users_v2에 초대된 사용자가 존재하며 invite_token이 null이 아님nc_base_users_v2에 대상 베이스에 대한 실제 멤버십 행이 존재함invited_by가 NULL임그런 다음 일반 가입 흐름을 통해 초대를 수락했습니다:
POST /api/v2/auth/user/signup
Content-Type: application/json
{
"email": "[email protected]",
"password": "Password123.",
"token": "<invite_token>"
}
반환된 xc-auth를 사용하여 다음을 호출했습니다:
GET /api/v2/meta/bases/<baseId>/tables
200 OK가 반환되었습니다.
마지막으로 소유자로서 공유 베이스 링크를 비활성화했습니다:
DELETE /api/v2/meta/bases/<baseId>/shared
이후:
xc-shared-base-id를 사용한 공유 링크 접근은 401 실패xc-auth를 사용한 초대된 계정은 200으로 계속 성공200200200200200401200이는 중앙 보안 주장을 입증했습니다:
한 번의 성공적인 공유 베이스 초대로도 이미 권한 부여 실패를 보여주기에 충분했을 것입니다.
그러나 전체 검증 체인은 두 가지 이유로 중요했습니다.
이것이 단순한 엔드포인트 노출이 아님을 보여주었습니다.
공개 공유 세션이 단순히 제한된 API에 도달한 것이 아닙니다. 전체 권한 전환 체인을 완료했습니다:
이것이 자체 취소되지 않음을 증명했습니다.
더 심각한 영향은 공유 링크 비활성화 후에 나타났습니다:
이것이 일시적인 링크 접근을 지속적인 접근 유지로 바꾼 것입니다.
이 취약점은 공유 베이스 링크를 가진 모든 사람이 다음을 수행할 수 있게 합니다:
주된 영향은 기밀성(confidentiality) 입니다. 공격자가 일반 인증된 계정을 통해 공유 베이스 데이터에 대한 지속적인 읽기 접근을 유지할 수 있기 때문입니다.
또한 무결성(integrity) 영향도 있습니다. 공개 공유 주체가 새 멤버를 추가하여 접근 제어 상태를 수정할 수 있기 때문입니다.
이는 일반적인 데이터 유출보다 더 강력한 결과입니다. 익명 공유와 인증된 멤버십 사이의 권한 경계 붕괴입니다.
이 문제는 기밀성 영향을 수반하는 교차 범위 권한 부여 결함으로 합리적으로 분류됩니다.
CVSS:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
해당 벡터는 여기서의 핵심 동작에 적합합니다:
수정 방향은 간단합니다.
공유 베이스 세션은 멤버 관리 기능을 상속해서는 안 됩니다.
최소한:
xc-shared-base-id를 통해 접근 가능한 모든 권한에서 baseUserList 및 userInvite 제거GET 및 POST /api/v2/meta/bases/:baseId/users와 같은 베이스 멤버십 엔드포인트를 호출할 수 없도록 명시적 차단 시행이 문제는 NocoDB 0.301.3의 커밋 dac49b0122c5ee655fb8f46a1b6e42dfeec1f3ad에서 로컬로 검증되었습니다.
보고서는 다음을 입증했습니다:
xc-shared-base-id에서 일반 베이스 역할로의 ACL 매핑해당 문제는 다음으로 할당되었습니다:
CVE-2026-46552
핵심 교훈은 간단합니다:
공유 링크 접근은 신뢰된 멤버십과 동일하지 않습니다.
많은 시스템이 이 두 개념을 동일한 역할 모델로 통합할 때 문제에 빠집니다.
공유 링크는 운영상 뷰어 계정과 유사해 보일 수 있지만, 신뢰 가정은 다릅니다:
이 낮은 보증의 주체가 관리 작업을 수행하거나 새로운 지속적인 신원을 생성할 수 있다면, 공유 경계는 이미 깨진 것입니다.
그것이 진짜 핵심입니다.