박연오

기술 분석 · ToolJet

워크스페이스 경계를 넘는 ToolJet DB 권한 검사 우회

ToolJet DB에서 워크스페이스 관리자 권한이 허용된 워크스페이스 밖에 적용된 원인과 명시적인 워크스페이스 검증으로 경계를 복원한 방식을 설명합니다.

관리자 권한의 범위

ToolJet DB는 워크스페이스 안의 애플리케이션을 위한 데이터베이스 테이블을 제공합니다. 제가 살펴본 질문은 테이블 관리 권한이 그 권한을 부여한 워크스페이스 안에서만 유효한지였습니다. 워크스페이스 A의 관리자 Mallory와 워크스페이스 B를 관리하는 Alice를 생각해 보겠습니다. Mallory는 A에서 정당한 관리자 권한을 갖지만, Alice의 테이블은 그 권한 범위 밖에 있습니다. 이 취약점은 Alice의 세션을 탈취한 상황이 아니라 Mallory 자신의 인증된 계정에 관한 것입니다.

원래의 로컬 평가에서는 ToolJet CE v3.20.188-lts와 v3.20.189-lts를 검증했으며, 이 경계를 넘어설 수 있음을 확인했습니다. ToolJet의 공개 보고서는 CVE-2026-73068을 명시하고, 심각도를 CVSS 3.1 기준 Moderate 6.8로 평가합니다.

아래 실행 관찰은 당시 평가에서 나온 결과입니다. 배포된 수정과의 비교는 이후에 수행한 소스 검토이며, 이 글을 작성하면서 취약점을 새로 재현하거나 패치된 릴리스의 실행 검증을 수행하지는 않았습니다.

워크스페이스 경계 확인

권한 검사가 무엇을 확인하는지와 테이블 작업이 어떤 자원에 영향을 줄 수 있는지를 비교했습니다. 검사는 호출자의 현재 워크스페이스 내 역할을 확인했습니다. 그러나 테이블 관리 작업은 영향을 받는 워크스페이스가 그렇게 허가된 범위와 일치하도록 요구하지 않았습니다. 따라서 A에서 확인한 권한이 B에도 적용될 수 있었습니다. 이 불일치가 공개 보고서에서 설명하는 원인입니다.

여기서는 세 가지 역할을 구분해야 합니다. 인증은 호출자의 신원과 워크스페이스 맥락을 확인합니다. 기능별 권한 검사는 호출자가 특정 유형의 작업을 수행해도 되는지 결정합니다. 워크스페이스 검증은 자원의 범위를 그 권한이 부여된 맥락에 연결합니다. 유효한 관리자라도 첫 두 검사를 통과했다는 사실만으로 세 번째 질문이 해결되지는 않습니다.

따라서 인증 가드가 존재한다는 사실만으로 이 보고를 기각할 수는 없었습니다. 기능별 검사를 제거하는 것도 올바른 수정이 아닙니다. 해당 워크스페이스에 속해 있다는 사실만으로 테이블 관리 권한이 주어지는 것은 아니기 때문입니다. 수정은 워크스페이스와의 관계 확인과 작업별 권한 검사를 모두 유지해야 합니다.

증거와 다른 설명의 검토

로컬 Docker 환경에서 일회성 표식 테이블을 사용해 동작을 재현했습니다. 평가한 두 버전의 보존된 결과는 아래 항목에서 일치하며, 같은 관찰이 공개 증거 요약에도 나옵니다.

관찰 항목 기록된 결과 확인할 수 있는 사실
일반적인 워크스페이스 접근 B로 전환하면 401이 반환되었고, 호출자에게 반환된 워크스페이스 목록에도 B가 없었습니다. 일반 워크스페이스 인터페이스는 해당 계정에 B의 접근 권한을 부여하지 않았습니다.
표식 생성 201이 반환되었고, B에 있는 표식의 개수는 1이었습니다. 응답 상태뿐 아니라 보호 대상의 실제 상태가 변경되었습니다.
독립적인 조회 권한이 있는 관리자의 조회에서 200이 반환되었습니다. 표식은 실제로 생성된 워크스페이스에서 보였습니다.
표식 삭제 200이 반환되었고, B에 있는 표식의 개수는 다시 0이 되었습니다. 허가되지 않은 작업으로 보호 대상 자원을 삭제할 수도 있었습니다.

접근 거부 결과가 중요한 이유는 이미 권한이 있는 관리자라면 경계 위반을 입증할 수 없기 때문입니다. 워크스페이스 목록은 이 비교 조건을 뒷받침하지만, 모든 소속 정보 저장소를 독립적으로 감사한 결과는 아닙니다. 나머지 핵심은 보호 대상의 실제 상태입니다. 성공 응답만으로는 무언가 바뀌었는지, 작업이 A에만 영향을 주었는지 판단할 수 없습니다. 로컬 테스트에서 B의 표식이 생성되고 삭제된 결과는 이러한 다른 설명을 배제합니다.

영향과 한계

검증에서 확인한 시작 조건은 다른 워크스페이스의 식별자를 알고 있는 인증된 워크스페이스 관리자였습니다. 테이블 생성과 삭제는 무결성과 가용성의 경계를 넘었으며, 보고서에는 테이블 메타데이터 노출도 기록되어 있습니다. 고객 데이터 유출, 인증되지 않은 접근 또는 원격 코드 실행이 입증된 것은 아닙니다. 평가에는 로컬 대상을 사용했으며, 영향을 받는 구성이 얼마나 널리 배포되어 있는지는 측정하지 않았습니다. 공개된 영향과 한계.

워크스페이스와 권한의 관계 복원

공개된 수정은 누락되었던 관계를 명시적으로 확인합니다. 다음은 server/src/modules/tooljet-db/controller.ts의 가드 선언을 v3.20.206-lts와 v3.20.207-lts 사이에서 비교한 핵심 부분입니다.

- @UseGuards(JwtAuthGuard, FeatureAbilityGuard)
+ @UseGuards(JwtAuthGuard, OrganizationValidateGuard, FeatureAbilityGuard)

수정 전 선언은 검토한 v3.20.188-lts 소스에도 존재합니다. 다음 링크는 발췌한 코드를 변경되지 않는 릴리스 커밋에 연결합니다. v3.20.188-lts 선언, v3.20.206-lts 선언, v3.20.207-lts 선언.

v3.20.207-lts의 server/src/modules/app/guards/organization-validate.guard.ts에서 OrganizationValidateGuard.canActivate는 다음과 같이 비교합니다.

const request = context.switchToHttp().getRequest();
const { organizationId } = request.params;
const user: User = request.user;
return user.organizationId === organizationId;

여기서 user.organizationId는 인증된 워크스페이스 맥락을 나타내고, organizationId는 요청한 범위를 식별합니다. 동등성 검사는 두 범위가 일치하도록 요구합니다. 이 검사는 인증이나 기능별 권한 검사를 대체하지 않고 함께 적용됩니다. 이 짧은 가드가 권한 정책 전체를 구성하는 것은 아니며, 주변의 인증된 요청 맥락에 의존합니다. 배포된 가드 구현.

이는 공급자의 수정에서 발췌한 코드로, 제가 작성한 패치도 수정 전체를 보여 주는 코드도 아닙니다. 업스트림 PR #17298은 컨트롤러와 기능별 권한 코드 모두를 변경합니다. 2026년 8월 4일 공개된 공식 v3.20.207-lts 릴리스는 이 PR을 포함한다고 명시합니다. 여기에 서술한 릴리스 반영 여부는 소스로 확인했으며, 패치된 릴리스에서 독립적인 실행 검증을 한 것은 아닙니다.

회귀 테스트에서는 다음 조건을 확인하고자 합니다. 아래 항목은 제안하는 테스트이며, 실행 결과나 업스트림 테스트의 검증 범위에 관한 주장이 아닙니다.

제안하는 사례 필요한 동작
허가된 역할이며 워크스페이스가 일치 정당한 테이블 관리가 계속 가능해야 합니다.
A에서 허가된 역할이지만 자원 범위는 B 접근을 거부하고 B의 보호 대상 상태를 변경하지 않아야 합니다.
워크스페이스는 일치하지만 역할의 권한이 부족 워크스페이스가 일치하더라도 작업을 거부해야 합니다.

당시 실행 검증을 수행한 두 버전과 세 소스 스냅샷은 구체적인 관찰을 뒷받침하지만, 취약점이 처음 도입된 시점이나 전체 영향 버전 범위를 확정하지는 않습니다. 다른 릴리스와 백포트는 여기서 개별적으로 평가하지 않았습니다. 남은 검증 단계는 배포된 수정에 대해 회귀 테스트를 실행하고, 작업 거부와 보호 대상 상태의 보존을 모두 확인하는 것입니다.