fix(core,board,ecommerce,payments,basic): KVE-2026 보안 게이트 6묶음 + 자격증명 전송로 정합

KISA 제보 취약점(KVE-2026-1914/1919/2019/2029/2041/2042/2043/2044)과
그 수정 과정에서 드러난 자격증명 전송로 결함을 함께 해소한다.

globalHeaders 는 데이터소스와 apiCall 핸들러에만 적용되는데, 코어 ApiClient 를
직접 부르는 경로들이 그 사실을 모른 채 게이트된 엔드포인트를 호출하고 있었다.
서버는 정당한 사용자를 거부하고 화면은 이미 버튼을 내준 뒤라, 예외도 로그도 없이
그 자리만 비는 형태로만 드러났다. 전송로 10축을 전수 열거해 6건을 고치고,
같은 실수가 반복되지 않도록 규정과 coverage 에 등재했다.

아웃바운드 프록시가 사이트 자기 자신으로 가는 내부 요청까지 가로채 저장이 수십 초씩
걸리던 문제도 함께 고쳤다. 실패가 폴백으로 삼켜져 화면에는 지연으로만 나타났다.
This commit is contained in:
HeuJung committed 2026-09-06 00:42:29 +09:00
1 parent 8f072895ff
commit 9cf9c3ff8c
104 files changed
+4522 -412

No files matched your search

@@ -312,12 +312,13 @@ ENV;
$merged = mergeRuntimeIntoEnv($envContent, $runtime);
$this->assertStringContainsString('DB_WRITE_HOST=real-host.example.com', $merged);
$this->assertStringContainsString('DB_WRITE_PORT=3307', $merged);
$this->assertStringContainsString('DB_WRITE_DATABASE=real_db', $merged);
$this->assertStringContainsString('DB_WRITE_USERNAME=real_user', $merged);
// 값은 전부 serializeEnvValue 를 지나 따옴표로 감싸진다 (개행 주입 차단 관문 일원화).
$this->assertStringContainsString('DB_WRITE_HOST="real-host.example.com"', $merged);
$this->assertStringContainsString('DB_WRITE_PORT="3307"', $merged);
$this->assertStringContainsString('DB_WRITE_DATABASE="real_db"', $merged);
$this->assertStringContainsString('DB_WRITE_USERNAME="real_user"', $merged);
$this->assertStringContainsString('DB_WRITE_PASSWORD="real_pass"', $merged);
$this->assertStringContainsString('DB_PREFIX=real_', $merged);
$this->assertStringContainsString('DB_PREFIX="real_"', $merged);
// Read 라인도 write 와 동기화되어 치환되어야 함
$this->assertStringNotContainsString('DB_WRITE_HOST=127.0.0.1', $merged);
@@ -350,10 +351,10 @@ ENV;
$this->assertStringContainsString("DB_READ_HOST=\n", $merged);
$this->assertStringContainsString("DB_READ_DATABASE=\n", $merged);
$this->assertStringContainsString("DB_READ_USERNAME=\n", $merged);
$this->assertStringNotContainsString('DB_READ_HOST=w-host', $merged);
$this->assertStringNotContainsString('DB_READ_DATABASE=wdb', $merged);
$this->assertStringNotContainsString('DB_READ_HOST="w-host"', $merged);
$this->assertStringNotContainsString('DB_READ_DATABASE="wdb"', $merged);
// write 라인은 정상 기록
$this->assertStringContainsString('DB_WRITE_HOST=w-host', $merged);
$this->assertStringContainsString('DB_WRITE_HOST="w-host"', $merged);
}
public function test_merge_uses_separate_read_when_specified(): void
@@ -369,8 +370,8 @@ ENV;
$merged = mergeRuntimeIntoEnv($envContent, $runtime);
$this->assertStringContainsString('DB_READ_HOST=r-host', $merged);
$this->assertStringContainsString('DB_READ_DATABASE=rdb', $merged);
$this->assertStringContainsString('DB_READ_HOST="r-host"', $merged);
$this->assertStringContainsString('DB_READ_DATABASE="rdb"', $merged);
}
public function test_merge_appends_db_lines_when_absent_from_template(): void
@@ -392,8 +393,8 @@ ENV;
$merged = mergeRuntimeIntoEnv($envContent, $runtime);
// .env.example 에 라인이 없는 비표준 케이스 — 끝에 추가
$this->assertStringContainsString('DB_WRITE_HOST=h', $merged);
$this->assertStringContainsString('DB_WRITE_DATABASE=d', $merged);
$this->assertStringContainsString('DB_WRITE_HOST="h"', $merged);
$this->assertStringContainsString('DB_WRITE_DATABASE="d"', $merged);
}
public function test_merge_preserves_db_lines_when_runtime_has_no_db(): void