🎲 초기화되지 않은 변수 시뮬레이터 KISA A-5 · 초기화되지 않은 변수 사용

지역 버퍼나 플래그를 대입 전에 읽으면 이전 호출이 스택에 남긴 잔존 바이트가 그대로 반환됩니다. 그 잔존값은 비밀을 유출하거나(정보 노출) 보안 분기를 비결정적으로 만들어(때때로 접근을 허용) 위험합니다.

① 정보 유출: 스택 재사용이 이전 비밀을 노출 VULNERABLE

handle_secret()가 16바이트 스택 버퍼에 토큰을 쓰고 반환합니다(바이트는 지워지지 않음). handle_public()이 같은 스택 프레임에 초기화되지 않은 char buf[16]를 선언해 클라이언트로 전송하면 — 잔존 토큰이 유출됩니다.
스택 프레임 버퍼 (16바이트 @ 0x7ffe...)

② 비결정적 분기: 초기화되지 않은 인증 플래그 VULNERABLE

bool isAdmin;이 선언되지만 항상 실행되지는 않는 if 안에서만 설정됩니다. 조건을 건너뛰면 isAdmin은 잔존 스택 바이트를 가지며 — 때때로 0이 아니어서 접근이 허용됩니다. 여러 번 실행해 결과가 뒤집히는 것을 보세요.

③ 안전: 선언 시 항상 초기화 SECURE

char buf[16] = {0};와 bool isAdmin = false;는 모든 바이트를 결정적으로 만듭니다. 버퍼는 이전 비밀을 절대 담지 않고 분기는 절대 뒤집히지 않습니다 — 명시적으로 허용하지 않으면 접근은 거부됩니다.
0으로 초기화된 버퍼

④ 취약 vs 안전 코드

VULNERABLE — C
void handle_public(int sock){
    char buf[16];          // 초기화 안 됨!
    // buf 에는 이전 호출(handle_secret)의
    // 토큰 바이트가 그대로 잔존
    send(sock, buf, 16, 0); // ← 비밀 유출

    bool isAdmin;          // 초기화 안 됨!
    if (parse_role() == 1) // 조건이 거짓이면
        isAdmin = true;    // ← 이 줄 건너뜀
    if (isAdmin)           // 잔존 바이트가 참일 수도
        grant_admin();     // ← 우발적 권한 상승
}
SECURE — C
void handle_public(int sock){
    char buf[16] = {0};    // 모든 바이트 0
    fill_public(buf);      // 의도한 값만 기록
    send(sock, buf, 16, 0); // 잔존 비밀 없음

    bool isAdmin = false;  // 안전한 기본값
    if (parse_role() == 1)
        isAdmin = true;
    if (isAdmin)           // 명시 허용 시에만 참
        grant_admin();
}
// 컴파일 시 -Wuninitialized / -Werror,
// MSAN(MemorySanitizer)로 조기 탐지
방어 핵심: 모든 변수를 선언 시 초기화(= 0 / = {0} / = false / 생성자) · 보안 플래그는 기본 거부(deny-by-default) · 비밀을 담은 버퍼는 재사용 전 0으로 소거 · CI에서 -Wuninitialized -Werror·MemorySanitizer 활성화.
⚠️ 교육용 시뮬레이션입니다. 스택 바이트·비밀·플래그는 모두 mock JS 값이며 실제 메모리를 초기화 없이 읽지 않습니다.