AI가 지금 당신에 대해 볼 수 있는 것은 무엇인가요? 스캐너를 직접 만들어 확인했습니다

발행: (2026년 3월 5일 오전 05:41 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

불편한 진실

지금 이 글을 읽고 있는 머신에는 아마도 수십 개의 비밀이 눈에 보이는 곳에 놓여 있을 것입니다.

OPENAI_API_KEY 가 환경 변수로 설정돼 있어 실행하는 모든 프로세스가 볼 수 있습니다. ~/.aws/credentials 파일에는 AWS 액세스 키가 평문으로 들어 있습니다. ~/.ssh/id_rsa 에는 패스프레이즈가 없는 SSH 개인 키가 있습니다. 여러 프로젝트 디렉터리마다 .env 파일이 세 개씩 존재하고, 각각에 데이터베이스 자격 증명과 토큰이 들어 있습니다. 클립보드에 한 시간 전 복사한 API 키가 아직 남아 있을 수도 있습니다.

이제 스스로에게 물어보세요: 로컬에서 실행되는 AI 어시스턴트가 이 모든 정보를 읽고 싶다면, 읽을 수 있을까요?
답은 거의 입니다.

저는 이를 구체화하기 위해 shadowscan 을 만들었습니다. 한 번의 명령으로 지금 바로 AI—또는 여러분과 동일한 권한으로 실행되는 어떤 프로세스가 읽을 수 있는 내용을 확인하세요.

shadowscan 이 하는 일

shadowscan 은 로컬 보안 스캐너입니다. 8가지 노출 카테고리를 검사하고 위험 등급이 매겨진 보고서를 생성합니다. 네트워크 호출은 전혀 없습니다. 모든 결과는 여러분의 머신에만 남습니다. 비밀 값은 항상 마스킹됩니다.

SHADOW SCAN REPORT
==================
[CRITICAL]  ~/.aws/credentials — AWS access key found
[HIGH]      ENV: OPENAI_API_KEY — API key exposed to all child processes  (sk-a****)
[HIGH]      ~/.ssh/id_rsa — Unencrypted SSH private key
[MEDIUM]    Dotenv file found: /home/user/project/.env — review manually
[LOW]       Clipboard — empty

Overall risk: CRITICAL  |  Findings: 5
Run 'shadowscan explain ' for details and fix instructions.

(sk-a****) 와 같은 마스킹 형식은 앞 네 글자를 보여주고 뒤에 **** 로 가립니다. 키를 식별할 수 있을 정도는 보여주지만, 실제로 사용할 수 있을 정도는 절대 노출되지 않습니다.

8가지 스캔 카테고리

카테고리무엇을 검사하는가
env비밀 패턴(*KEY*, *TOKEN*, *SECRET*, *PASSWORD*, …)과 일치하는 환경 변수
creds~/.aws/credentials, ~/.netrc, ~/.pypirc, ~/.npmrc
ssh~/.ssh/id_* — 암호화되지 않은 개인 키
dotenv현재 디렉터리와 홈 디렉터리(최대 2단계 깊이) 내 .env 파일
clipboard클립보드 내용 — 휴리스틱을 통해 비밀을 감지
mcpClaude와 Cursor MCP 설정 파일에 포함된 API 키
git실수로 커밋된 비밀을 찾기 위해 최근 50개의 커밋 검사
tmp/tmp/ 에 있는 민감해 보이는 이름의 파일

MCP 설정 스캐너는 종종 사람들을 놀라게 합니다. Claude Desktop이나 Cursor를 사용한다면, MCP 설정 파일에 API 키가 JSON 안에 직접 삽입돼 있을 수 있습니다. 대부분의 개발자는 한 번 설정하고는 다시 생각하지 않으니, 놓치기 쉽습니다.

내부 동작 방식

각 스캐너는 하나의 추상 기본 클래스를 상속받습니다:

from abc import ABC, abstractmethod
from shadowscan.models import Finding

class BaseScanner(ABC):
    """All scanners must inherit from this and implement scan()."""

    @abstractmethod
    def scan(self) -> list[Finding]:
        """Run the scanner and return a list of findings."""
        ...

    def redact(self, value: str) -> str:
        """Return first 4 characters of value followed by '****'."""
        if len(value)

이 기본 클래스는 모든 스캐너가 반드시 구현해야 하는 scan() 메서드를 정의하고, 비밀 값을 마스킹하는 redact() 헬퍼를 제공합니다.

0 조회
Back to Blog

관련 글

더 보기 »