업데이트로 돌아가기
New releaseAug 6, 2026

SecureAI-Scan v0.8.0

SecureAI-Scan은 AI 기반 앱에 특화된 보안 문제(프롬프트 인젝션, MCP 도구 남용, RAG 데이터 오염, 에이전트 신뢰 위반 등)를 찾기 위해 TypeScript 및 JavaScript 코드베이스를 스캔하는 CLI 도구입니다.

공유

SecureAI-Scan

npm version npm downloads CI CodeQL OpenSSF Scorecard license Node OWASP

TypeScript, JavaScript, Python 코드에서 LLM, MCP, Agent Skill, RAG 위험을 스캔하는 오프라인 CLI — import 해석 기반 데이터 흐름 증거, 기본 오탐(false positive) 0건, OWASP LLM/ASI/MCP Top 10에 매핑.

이 분야의 대부분 스캐너는 키워드를 패턴 매칭한 뒤 이를 발견 항목으로 간주합니다. SecureAI-Scan은 실제 import 해석된 코드를 통해 실제 소스 → 흐름 → 싱크 경로를 추적하며, 기본 스캔은 증명할 수 있는 것만 보여줍니다. 계정 불필요, 클라우드 업로드 없음, 어떤 데이터도 머신을 벗어나지 않습니다.

공식 OWASP Top 10 for LLM Applications 2026, Top 10 for Agentic Applications (2026), 그리고 MCP Top 10을 출시 주부터 모두 다룹니다.

30초 만에 시작하기```bash

npx --yes [email protected] scan .

계정, 클라우드 업로드, Python 인터프리터, 또는 구성이 필요하지 않습니다. TypeScript, JavaScript, Python, MCP 구성, 그리고 Agent Skill 번들은 자동으로 감지됩니다.

**측정된 `0.9.0` 릴리스 후보:** 136/136 테스트 · 88.08% 문장 커버리지 · 9개 공개 저장소의 12,676개 파일 · 검토된 기준선 대비 신규 기본 계층 지문 0건. [증거](https://github.com/akanthed/secureai-scan/blob/main/docs/benchmarks/v0.9.0.json) · [방법론 및 한계](https://github.com/akanthed/secureai-scan/blob/main/docs/ReleaseAssurance.md)```
  ▌ HIGH  AI001  Prompt injection via user input
    PROVEN  LLM01:2026 Prompt Injection

    source src/chat.ts:8   request data `req.body.input`
    flow   src/chat.ts:13  passed as `systemPrompt`
    sink   src/chat.ts:10  openai.chat.completions.create — system role (OpenAI)

    fix    Keep system prompts static; pass user input as a user-role message.

이것이 당신을 위한 것인가요? SecureAI-Scan은 의도적으로 LLM, MCP, RAG/에이전트 위험 — 프롬프트 인젝션, 도구 중독, 안전하지 않은 출력 처리, 벡터 스토어 접근 제어, 에이전트 스킬 중독 — 에 범위를 한정합니다. 일반적인 SAST 또는 시크릿 스캐너가 아니며, 그렇게 되려고 하지도 않습니다. LLM 형태의 페이로드가 없는 알려진 악성 패키지(예: 이메일 API 호출에 하드코딩된 유출 주소)는 패턴 규칙이 아닌 오프라인 권고 목록(DEP003)으로 탐지됩니다. 코드베이스가 LLM, MCP 서버, 벡터 스토어와 통신하거나 Agent Skills를 제공한다면, 이 도구는 당신을 위해 만들어졌습니다.

새 기능: LiteLLM Proxy(config.yaml)에 대한 정적 구성 스캔 — 하드코딩된 시크릿, 평문 공급자 엔드포인트, 누락된 가드레일. Rules(LLC001–LLC003) 참조.

목차

이 스캐너가 다른 이유

  • 증거 계층, 노이즈가 아님. 모든 발견 사항은 proven(추적된 데이터 흐름 또는 파싱된 구성 사실), likely(해석된 싱크, 휴리스틱 1단계), 또는 heuristic입니다. 기본 스캔은 proven + likely만 표시합니다. 휴리스틱은 --paranoid를 통해 선택적으로 활성화됩니다.
  • Import 해석 기반 탐지. 호출이 실제 SDK import(openai, @anthropic-ai/sdk, ai, @google/genai, LangChain, Bedrock, …)로 해석될 때만 "LLM 호출"로 간주됩니다. Google Maps 클라이언트가 다시 LLM으로 플래그 지정되는 일은 없습니다.
  • 정밀도 게이트 방식, 실제 저장소로 벤치마킹. 테스트 스위트는 모든 취약한 픽스처가 탐지되고 모든 안전한 픽스처가 깨끗하게 유지됨을 검증합니다 — 안전한 코퍼스의 오탐은 빌드를 실패시킵니다. 그 외에도 npm run regression은 실제 공개 저장소(OpenAI/Anthropic/Vercel AI SDK, 공식 MCP 서버, LlamaIndex)를 커밋된 수동 검토 기준선과 대조하여 스캔하고, 새로운 proven/likely 발견 사항이 있으면 실패합니다. 실제 전후 수치는 Testing & benchmarking을, 그 배경 이야기는 What we found scanning real repos를 참조하세요 — 레이블이 지정된 악성 스킬 코퍼스에서 6/6 탐지율, 그리고 라이브러리 수준의 정직한 발견 사항에 대해 llama_index를 "취약"하다고 부르지 않는 이유. Discussion write-up →
  • GitHub 코드 스캐닝용 SARIF. --output report.sarif는 풀 리퀘스트와 Security 탭에 발견 사항을 인라인으로 표시합니다.
  • AI-BOM. secureai-scan bom .은 SDK, 모델 ID, 벡터 스토어, 에이전트 프레임워크, MCP 서버의 구문 기반 인벤토리를 구축하여 OWASP LLM Top 10 / EU AI Act 문서화 요구 사항에 매핑합니다.
  • MCP 구성 스캔. .mcp.json, claude_desktop_config.json, .cursor/mcp.json을 파싱합니다: 고정되지 않은 npx -y 서버, 인라인 시크릿, 평문 HTTP 전송.
  • MCP 도구 중독 탐지. WhatsApp MCP 러그풀과 postmark-mcp 백도어 뒤의 패턴 — 보이지 않는 유니코드, 에이전트 지시 인젝션 문구, 도구 이름/설명의 교차 도구 섀도잉 — 을 서버를 실행하기 전에 정적으로 탐지합니다.
  • MCP 명령 인젝션 탐지. 요청 데이터로 구축된 MCP stdio 전송 command/args를 플래그 지정합니다 — 2026 MCP STDIO RCE 공개 뒤의 패턴.
  • Agent Skill 중독 탐지. 동일한 보이지 않는 유니코드, 인젝션 문구, 섀도잉 검사를 SKILL.md 파일에 적용합니다 — Agent Skills는 전체를 컨텍스트에 로드하므로, 중독된 스킬은 다른 이름의 중독된 도구 설명입니다.
  • 회피 저항형 스킬 스캔. 스킬 번들은 SKILL.md뿐만 아니라 디렉토리로 스캔되며, 모든 콘텐츠 검사는 난독화 해제된 텍스트 변형에 대해 실행됩니다. 이는 Cloak and Detonate(arXiv:2607.02357)에서 조사된 9개 스캐너의 >90%를 우회한 공개 기법 — 호모글리프, 제로폭 분할, .git/ 또는 build/에 스테이징된 페이로드, *.test.ts 파일에 숨겨진 유출 — 을 대상으로 합니다. Evasion resistance 참조.
  • 알려진 취약 및 알려진 악성 패키지 권고, 버전 인식. 모든 의존성과 MCP로 실행되는 모든 패키지를 번들된 권고 스냅샷 — 문서화된 실제 백도어의 수동 선별 목록과 LLM/MCP/RAG 패키지 워치리스트에 대한 HIGH/CRITICAL OSV 권고 — 과 대조하여 확인합니다. scripts/sync-advisories.js로 재생성됩니다. 플래그 없이 모든 스캔에서 오프라인으로 실행됩니다. CVE는 고정된 버전이 영향 범위 내에 증명 가능하게 있을 때만 발생하며, 문서화된 악성 패키지는 모호한 범위에서도 발생합니다. 백도어 설치는 복구 불가능하기 때문입니다.
  • 로컬 우선. 어떤 것도 머신을 떠나지 않습니다.

비교

SecureAI-Scan은 일반 SAST 도구나 컨테이너/IaC 스캐너의 대체재가 아닙니다 — 대신이 아니라 함께 실행하세요. LLM/MCP/RAG 공격 표면을 위해 특별히 설계되었으며, 평면적인 키워드 발견 사항보다 데이터 흐름 증거를 강조합니다.

SecureAI-ScanSemgrep (OSS 규칙)TrivyGitHub Advanced Security
프롬프트 인젝션(소스→싱크 추적)✅ import 해석 데이터 흐름⚠️ 패턴 규칙만, 커뮤니티 유지⚠️ CodeQL 가능하지만 AI 전용 규칙셋 없음
MCP 도구 중독 / 구성 위험✅ MCP007–010, 구성 스캐너
Agent Skill 중독(SKILL.md)✅ 회피 저항, 번들 인식
RAG / 벡터 스토어 잘못된 구성✅ VEC001–004
알려진 악성 AI 패키지 권고✅ DEP003, 오프라인, 버전 인식⚠️ 일반 CVE 피드, AI 전용 아님⚠️ Dependabot, 일반 CVE 피드
일반 SAST(SQLi, XSS, 경로 탐색)❌ 설계상 범위 외
컨테이너 / IaC 스캔⚠️ CodeQL/Actions 통해
증거 계층(proven/likely/heuristic)❌ 발견 사항은 평면적⚠️ CodeQL 일부 있음, AI 튜닝 아님
SARIF 출력(GitHub 코드 스캐닝)기본 제공
오프라인 실행, 계정 불필요✅ (OSS 규칙)❌ GitHub 필요

이미 Semgrep 또는 GHAS를 실행 중이라면 유지하세요 — SecureAI-Scan은 그들이 전혀 모델링하지 않는 위험 표면을 위해 추가하세요.

먼저 질문하고 싶으신가요? 무료 **SecureAI-Scan AI Security Advisor on ChatGPT**를 사용해 보세요.

GitHub이나 Twitter에서 찾은 MCP 서버를 실행하려고 하시나요? 먼저 도구 설명을 **MCP X-Ray**에 붙여넣으세요 — 설치 없이 브라우저에서 숨겨진 유니코드, 인젝션된 지시, 알려진 악성 패키지를 확인합니다.

작동 확인

secureai-scan scan .을 실제(작고 의도적으로 취약한) 파일에 대해 처음부터 끝까지 실행한 실제 출력 — 소스:

추적된 프롬프트 인젝션 취약점을 찾는 secureai-scan scan .의 터미널 녹화

스캐너가 끝까지 추적하는 공격 형태:

MCP 도구 중독 데이터 흐름RAG 컨텍스트 인젝션 데이터 흐름
MCP 공격 추적RAG 중독 추적

명령어

95%의 경우 필요한 명령어:```bash secureai-scan scan .

그 외 필요한 것은 모두 준비되어 있습니다. `secureai-scan scan . --help`를 실행하면 터미널에서 이 모든 내용을 동일한 그룹으로 확인할 수 있습니다:

**일상 사용**

| 플래그 | 기능 |
|------|---------------|
| *(없음)* | `proven` + `likely` 등급 발견 항목 — 기본값이며 플래그가 필요 없습니다 |
| `--paranoid` | `heuristic` 등급 발견 항목도 포함 |
| `-s, --severity <level>` | `low`\|`medium`\|`high`\|`critical` 이상의 발견 항목만 표시 |
| `--output <file>` | 전체 보고서 작성 — `.sarif`(GitHub 코드 스캐닝), `.json`, `.md` 또는 `.html` |

**실행할 규칙 범위**

| 플래그 | 기능 |
|------|---------------|
| `-r, --rules <list>` | 지정한 규칙 ID만 실행(예: `AI001,MCP007`) |
| `--only-ai` / `--only-mcp` / `--only-vec` / `--only-skl` | 규칙 카테고리 하나만 실행 |
| `--check-dependencies` | `package.json`/`requirements.txt`를 npm/PyPI 레지스트리와 대조하여 오타 및 환각 패키지(`DEP001`/`DEP002`) 확인. `-r`로 해당 규칙을 직접 선택하면 자동 활성화되므로 둘 다 전달할 필요가 없습니다. 항상 오프라인으로 실행되는 `DEP003`(악성 패키지)에는 필요하지 않습니다 |

**CI / 워크플로우**

| 플래그 | 기능 |
|------|---------------|
| `--fail-on <severity>` | 해당 심각도 이상의 발견 항목이 있으면 `1`로 종료 |
| `--baseline <file>` | 저장된 기준선 대비 새로 발생하거나 변경된 이슈만 추적 |
| `--policy <file>` | `.secureai-policy.json`에서 임계값, 건너뛸 경로, 차단할 규칙 로드(파일이 있으면 자동 감지 — `secureai-scan init`으로 생성 가능) |

**고급**

| 플래그 | 기능 |
|------|---------------|
| `--min-confidence <0-1>` | `--paranoid`보다 세밀한 제어: 정확한 신뢰도 점수(`0.9` proven / `0.65` likely / `0.35` heuristic) 미만의 발견 항목 숨김 |
| `--limit <n>` | 터미널에 표시할 최대 규칙 그룹 수(기본값 `10`) — 전체 상세 내용은 항상 `--output`으로 출력 |
| `--debug` | 스캔한 모든 파일과 실행된 규칙 출력 |

**설치 전에 스캔 — 클론도, 설정도 필요 없음:**```bash
secureai-scan skill anthropics/skills          # a GitHub "owner/repo" shorthand
secureai-scan skill https://github.com/…       # or a full git URL
secureai-scan skill ./some/local/skill-dir     # or a local path
secureai-scan mcp some-mcp-server-package      # a bare npm package name
secureai-scan mcp owner/mcp-server-repo        # or git, same as `skill`

skillmcp는 대상을 가져와서 스캔한 다음, 가져온 복사본을 삭제합니다(--keep를 사용하면 대신 검사할 수 있습니다). 가져온 것은 절대 실행되지 않습니다: npm 대상은 npm pack으로 다운로드되며 — tarball만, install도, 라이프사이클 스크립트도 없습니다 — git 대상은 일반 git clone --depth 1입니다. 이것이 가장 중요한 순간입니다: 스킬이 ~/.claude/skills/에 들어가거나 서버가 .mcp.json에 들어가기 전이지, 그 후가 아닙니다.

기타 명령어:```bash secureai-scan bom . --output AI_BOM.md # AI Bill of Materials secureai-scan explain AI001 # why + exploit + fix example, for any rule secureai-scan threat-model . # THREAT_MODEL.md with the OWASP coverage matrix — example: docs/examples/THREAT_MODEL.example.md secureai-scan init # policy file + CI workflow, one-time setup

코드에서 검토된 결과를 억제합니다:```ts
// secureai-ignore AI001: reviewed, input sanitized via allowlist

GitHub Action```yaml

name: SecureAI-Scan on: [pull_request] permissions: contents: read security-events: write jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: akanthed/[email protected] with: scanner-version: 0.10.0 fail-on: high

PR에 인라인 주석과 저장소의 보안 탭에 결과가 표시됩니다. (`secureai-scan init`은 CLI를 직접 사용하여 동일한 워크플로를 생성합니다.)

스캔 결과가 깨끗한가요? 자신의 README에 배지를 추가하세요:```md
[![secureai-scan](https://img.shields.io/badge/secureai--scan-passing-brightgreen)](https://github.com/akanthed/SecureAI-Scan)

Pre-commit 훅

결과가 푸시되기 전에 발견하는 것을 선호하시나요? GitHub Action 대신 또는 그와 함께 이 저장소를 pre-commit 훅 소스로 추가하세요:```yaml repos:

훅은 모든 커밋에서 전체 프로젝트를 스캔합니다(변경된 파일만 스캔하는 것이 아니라 — 파일 A로의 데이터 흐름 추적은 파일 B에 의존할 수 있는데, 부분 스캔은 이를 놓칠 수 있습니다) 그리고 기본적으로 `high`+ 심각도 발견 사항에서 커밋을 차단합니다. 자체 구성에서 임계값을 재정의하세요:```yaml
      - id: secureai-scan
        args: ["--fail-on", "critical"]

규칙

42개 규칙, 공식 OWASP Top 10 for LLM Applications(2026)에 매핑 — 해당되는 경우 OWASP Top 10 for Agentic Applications(2026, ASI), OWASP MCP Top 10(2025), EU AI Act 조항도 포함. 버전별 2026 적용 범위 및 한계 참조; threat-model은 각 스캔 대상 프로젝트에 대한 매트릭스를 렌더링합니다.

규칙검증 내용OWASP
AI001사용자 입력이 시스템/개발자 프롬프트로 유입됨(소스 → 싱크 추적, 함수/파일 경계를 넘어 포함)LLM01
AI002프롬프트 내용 또는 비밀값이 로그에 기록됨(LLM SDK를 사용하는 파일에서)LLM02
AI003요청 핸들러에서 인증 검사 없이 LLM 호출이 발생함LLM06
AI004전체 사용자/세션 객체가 프롬프트로 직렬화됨(필드 선택은 플래그되지 않음)LLM02
AI005LLM 출력이 eval/exec/SQL/HTML 싱크에 도달함LLM10
AI006고영향 도구(삭제, 결제, 배포 등)가 승인 게이트 없이 노출됨LLM03
AI007검색된 RAG 콘텐츠가 권한 있는 프롬프트에 삽입됨LLM01
AI008시스템 프롬프트 텍스트에 비밀값이 포함됨LLM08
AI009무제한 사용자 입력 / 토큰 한도 누락LLM06
AI010가져온 외부 콘텐츠가 프롬프트로 유입됨LLM01
AI011에이전트 출력이 다운스트림 호출에서 시스템 역할로 승격됨LLM03
AI012LLM 출력이 스키마 검증 없이 파싱됨LLM10
MCP001MCP 도구 메타데이터가 검증 없이 시스템 프롬프트에 도달함LLM01
MCP002MCP 서버 URL이 사용자 입력으로 구성됨LLM04
MCP003MCP 도구 결과가 시스템 역할로 승격됨LLM10
MCP004MCP 서버가 고정되지 않은 npx -y 패키지로 실행됨LLM04
MCP005커밋된 MCP 구성에 비밀값이 인라인으로 포함됨LLM02
MCP006MCP 서버가 평문 HTTP로 실행됨LLM04
MCP007MCP 도구 이름 또는 설명에 보이지 않는/양방향 유니코드가 숨겨져 있음LLM01 · MCP03
MCP008MCP 도구 설명에 에이전트 지시 주입 문구가 포함됨LLM01 · MCP03
MCP009다른 도구로 호출을 유도하는 도구 설명(섀도잉)LLM01 · MCP03
MCP010MCP stdio 서버 명령/인자가 사용자 입력으로 구성됨(RCE)LLM04 · MCP05
SKL001에이전트 스킬 번들 어디에든 보이지 않는/양방향 유니코드가 존재함LLM01
SKL002스킬 설명 또는 본문에 에이전트 지시 주입 문구가 포함됨(난독화를 통한 매칭)LLM01
SKL003스킬 콘텐츠가 다른 스킬의 사용 시점/방식을 조종함(섀도잉)LLM01
SKL004단계적/자체 추출 페이로드: 불투명 블롭 + 디코딩 및 실행 지침LLM04 · MCP04
SKL005번들 동반 파일에서 자격 증명 읽기 + 하드코딩된 외부 이그레스LLM02 · MCP04
SKL006Claude Code의 동적 컨텍스트 주입 구문(!`cmd`/```!)을 통한 로드 시 명령 실행, 도구 권한 게이트 이전에 발생LLM04 · MCP05
SKL007스킬의 allowed-tools 프론트매터에 범위 제한 없는 Bash 권한 부여LLM03
SKL008스킬이 외부 URL에서 지침을 가져와 에이전트가 이를 따르도록 지시함("Circus of Skills")LLM04
SKL009스킬이 다른 컨텍스트 파일(MEMORY.md/SOUL.md/AGENTS.md/CLAUDE.md)에 기록하여 백도어를 유지함LLM05
SKL010스킬 프론트매터 또는 번들 구성 파일에 안전하지 않은 YAML/JSON 역직렬화 태그LLM04
VEC001테넌트/사용자 필터 없는 벡터 검색LLM09
VEC002무제한 또는 사용자 제어 검색 한도LLM06
VEC003사용자 콘텐츠가 공유 벡터 저장소에 수집됨LLM05
VEC004테넌트/네임스페이스 태깅 없는 수집LLM09
DEP001레지스트리에서 찾을 수 없는 종속성 이름(옵트인 --check-dependencies)LLM04
DEP002인기 패키지와 한 글자 차이인 종속성 이름(옵트인)LLM04
DEP003문서화된 악성 릴리스 또는 중요 CVE가 있는 종속성 — 모든 스캔에서 오프라인으로 확인, 버전 범위 인식(postmark-mcp, mcp-remote CVE-2025-6514 등)LLM04 · MCP04
LLC001LiteLLM 프록시 config.yaml에 하드코딩된 비밀값LLM02
LLC002LiteLLM 프록시 api_base가 평문 HTTP로 접근 가능LLM04
LLC003LiteLLM 프록시 구성에 guardrails: 섹션 없음(휴리스틱, --paranoid 전용)LLM03

secureai-scan explain <RULE_ID>는 모든 규칙에 대한 익스플로잇 워크스루와 전/후 코드 예제를 제공합니다.

아키텍처

세 개의 독립적인 스캔 표면이 하나의 병합되고 중복 제거된 발견 목록으로 이어집니다:``` ┌─────────────────────┐ *.ts / *.js ───▶ │ ts-morph AST rules │───┐ │ (import-resolved │ │ │ sinks + dataflow) │ │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ ┌──────────────┐ ┌─────────────────┐ *.py ───▶ │ tree-sitter AST + │───┼───▶ │ scan.ts │───▶ │ evidence filter │ │ local taint flow │ │ │ merge/dedupe│ │ → confidence │ └─────────────────────┘ │ │ + suppress │ │ → severity │ │ │ (// secure- │ │ → baseline diff │ .mcp.json, ┌─────────────────────┐ │ │ ai-ignore) │ │ → report │ SKILL.md ───▶ │ Config/bundle scan │──┘ └──────────────┘ └─────────────────┘ │ (off-disk, evasion- │ │ │ resistant) │ ▼ └─────────────────────┘ terminal · sarif · json · md · html

package.json, requirements.txt ─▶ dependency-guard.ts (advisories.ts, offline, version-aware)

Every AST rule only calls a function an "LLM call" if it resolves through real imports to a known SDK — never by name-matching alone. See [`docs/Architecture.md`](https://github.com/akanthed/secureai-scan/blob/main/docs/Architecture.md) for the full breakdown of each surface, and [`docs/DetectionEngine.md`](https://github.com/akanthed/secureai-scan/blob/main/docs/DetectionEngine.md) for how the evidence-tier contract works.

## MCP server (use it from Claude)

The package ships an MCP server exposing `scan_repository`, `explain_rule`, `generate_bom`, and `scan_untrusted_target` (fetch and scan a skill or MCP server before Claude recommends installing it — same fetch-without-executing behavior as the `skill`/`mcp` CLI commands):```json
{
  "mcpServers": {
    "secureai-scan": {
      "command": "node",
      "args": ["/path/to/secureai-scan/mcp-server/index.js"]
    }
  }
}

Claude Skill

Claude Code / Claude.ai 사용자를 위해, skills/secureai-scan/SKILL.md는 Claude가 언제 스캔을 실행해야 하는지(AI/LLM 코드 검토, 또는 MCP 서버/Agent Skill을 설치하기 전에 확인)와 결과를 읽는 방법을 가르칩니다 — 위의 MCP 서버와 달리 별도 프로세스를 실행할 필요가 없습니다. 사용하려면 skills/secureai-scan/ 디렉터리를 .claude/skills/로 복사하세요.

회피 저항성

2026년 7월, 두 건의 공개 연구에서 Agent Skill 스캐너가 사소하게 우회된다는 사실이 밝혀졌습니다.

Cloak and Detonate (Ji, Xu, Li, Gao, Wei, Wang & Cheung — HKUST, arXiv:2607.02357)는 1,613개의 실제 악성 스킬을 사용하여 9개의 공개된 스킬 스캐너에 대한 적대적 연구를 수행했습니다. 두 가지 공격 계열 모두 페이로드를 정확히 보존합니다:

  • Reify — 규칙이 매칭하는 바이트를 다시 작성하되, 에이전트가 런타임에 원본을 재조립하도록 합니다. 대부분의 정적 스캐너에서 >80% 우회율.
  • Disperse / SFS packing — 페이로드를 규칙의 범위 밖으로 이동: 스캐너가 건너뛰는 디렉터리로, 이름이 바뀐 확장자 뒤로, 또는 .git/에 아카이브 및 인코딩하여 넣고, 첫 실행 시 이를 재구성하는 무해한 커버 SKILL.md를 둡니다. 테스트된 모든 스캐너에서 ≥90% 우회율, 대부분에서 ≥96%. 한 하이브리드 스캐너의 탐지율은 ~99%에서 ~10%로 떨어졌습니다.

별도로, Gecko Security (VentureBeat)는 *.test.ts 파일에 페이로드를 배포했습니다. 모든 공개 스캐너가 이를 건너뛰었지만 — Jest와 Vitest는 다음 npm test에서 해당 파일을 자동으로 발견하고 실행합니다.

SecureAI-Scan은 각 공개된 기법을 처리합니다. 아래 각 행에는 test/deobfuscate.test.js의 해당 테스트 또는 test-fixtures/vulnerable/skills/의 픽스처가 있습니다:

기법 (논문 명칭)예시처리 방식
제로폭 삽입Ign‍ore all pre‍vious…텍스트가 보이지 않는 문자 제거 변형과 매칭됨
혼동 가능 글리프сurl (키릴 문자 с)매칭 전에 동형 글리프를 ASCII로 접기
대소문자 변환EvAl모든 콘텐츠 패턴이 대소문자 구분 없음
변수 분할'cu' + 'rl'매칭 전에 인접한 문자열 리터럴 결합
줄 단위 분할eval(x)단어 내 줄바꿈을 추가 변형으로 결합
파일별 추출소스된 헬퍼의 페이로드SKILL.md뿐만 아니라 전체 번들이 스캔됨
디렉터리 이동scripts/x.shbuild/x.sh번들 내 디렉터리 건너뛰기 목록 없음
확장자 변경x.shx.txt파일이 확장자가 아닌 콘텐츠로 스캔됨
크기 패딩스캐너의 한도를 넘도록 패딩초대형 파일은 헤드 읽기로 처리, 건너뛰지 않음
SFS packing.git/skillpack.dat의 페이로드번들의 .git/ 아래 비-git 파일은 proven으로 처리됨 (SKL004)
테스트 파일 스테이징*.test.ts의 페이로드번들 스캔은 의도적으로 테스트 경로를 강등하지 않음 (SKL005)

이것이 정밀도 계약을 약화시키지 않음

난독화 해제는 일반적으로 정밀도 위험입니다 — 매칭이 더 많아지면 노이즈도 더 많아집니다. 여기서 논리는 반전됩니다: 난독화 해제 후에만 나타나는 매칭은 강등이 아니라 proven으로 승격됩니다. 일반 문서에는 "ignore previous instructions" 안에 제로폭 조이너가 포함되지 않으며, curl 안에 키릴 문자 с도 포함되지 않습니다. 은닉 자체가 의도의 긍정적 증거입니다.

비교는 원시 매칭의 집합에 대한 것이며, 단순히 "원시 텍스트가 전혀 매칭되었는가"가 아닙니다 — 그렇지 않으면 공격자가 무해한 문구 하나를 평문으로 남겨 신호를 가릴 수 있습니다.

두 개의 새 번들 규칙은 키워드가 아닌 접속사에서만 발동합니다:

  • SKL004는 불투명한 블롭 해당 블롭을 이름으로 참조하는 압축 해제 지시문이 필요합니다 — 관련 없는 바이너리 자산 옆에 tar -x를 언급하는 README만으로는 충분하지 않습니다. 실제 아카이브(gzip/zip/png/pdf/wasm — 확장자가 아닌 매직 바이트로 확인)는 압축 방식과 관계없이 처음부터 "불투명"하지 않습니다.
  • SKL005는 구체적인 자격 증명 신호 — 경로(~/.aws/credentials, "token"이라는 단어가 아님) 또는 대량 환경 변수 열거(os.environ.items(), os.environ["API_KEY"]가 아님) — 하드코딩된 비로컬 호스트로의 이그레스가 같은 파일 내 25줄 이내에 있어야 하며, 또는 하나 이상의 이름 변경을 통해 재할당된 후 실행되는 원격 페치가 필요합니다. 한 함수에서 ~/.npmrc를 읽고 40줄 뒤에 레지스트리를 호출하는 게시 헬퍼는 깨끗하게 유지되며, API 호출을 위해 명명된 환경 변수 하나를 읽는 것은 절대 플래그되지 않습니다 — 두 형태 모두 안전 픽스처로 고정되어 있습니다.

우리가 직접 작성한 픽스처뿐만 아니라 두 개의 실제 세계 코퍼스로 검증됨: anthropics/skills의 18개 실제 스킬 번들 전체에서 0건의 발견 및 vercel/ai의 14개 전체, 그리고 cisco-ai-defense/skill-scanner의 라벨링된 평가 코퍼스에서 6/6 정확 (각각 _expected.json 판정이 있는 20개 스킬) — 안전으로 라벨링된 모든 항목에서 거짓 양성 0건. 테스트 및 벤치마킹 참조.

이것이 아닌 것

정직한 한계: 논문의 결론은 런타임 폭파가 정적 분석보다 낫다는 것이며, 이는 맞습니다. 이 규칙들을 아는 적응형 공격자는 이 규칙들이 다루지 않는 변환을 작성할 수 있습니다. 여기서 바뀌는 것은 회피의 비용입니다 — 공개되고 현재 유통되는 기법은 더 이상 작동하지 않으며, 이를 무찌르는 데 필요한 난독화는 이제 그 자체로 발견의 심각도를 높입니다. 정적 스캐닝은 필터이지 보안 경계가 아닙니다. 스캐너가 무엇을 말하든 신뢰할 수 없는 스킬을 신뢰할 수 없는 코드로 취급하세요.

신뢰 및 릴리스 보증

  • CI는 지원되는 Node 버전에서 Linux, Windows, macOS에서 실행됩니다.
  • CodeQL, 프로덕션 의존성 감사, OpenSSF Scorecard, Dependabot 및 이 스캐너 자체의 차단 자체 스캔이 독립적 검사를 제공합니다.
  • 모든 수동 npm 게시는 prepublishOnly를 통해 테스트, 커버리지 하한, 검토된 실제 저장소 회귀 게이트 및 tarball 검사를 호출합니다.
  • GitHub Actions는 npm 비밀번호나 토큰을 받지 않으며 패키지를 게시할 수 없습니다.
  • 릴리스 보증, 단일 유지관리자 거버넌스, 보안 보고버전별 벤치마크 증거는 공개되어 있습니다.

이 프로젝트는 계약상 SLA나 독립 인증이 없는 단일 유지관리자 프로젝트입니다. 위의 통제는 위험을 줄입니다; 정적 스캔을 보안의 증거로 바꾸지는 않습니다.

정밀도 계약

거짓 양성은 스캐너를 죽입니다. SecureAI-Scan의 규칙 엔진은 세 가지 엄격한 규칙을 따릅니다:

  1. 싱크는 임포트를 통해 해석됩니다. 식별자가 LLM SDK가 아닌 모듈로 해석되면 이름이 무엇이든 확실히 LLM 호출이 아닙니다.
  2. 증거는 라벨링되며 혼합되지 않습니다. 추적된 데이터플로우와 단어 근접 매칭은 같은 것이 아니므로 계층을 공유하지 않습니다.
  3. 안전 코퍼스가 모든 릴리스를 게이트합니다. test-fixtures/safe/에는 거짓 양성을 유발하던 패턴(비식별화된 PII 페이로드, Google Maps 클라이언트, LLM 클라이언트 옆의 환경 변수 API 키, 일반 응답 로깅, OAuth 메타데이터 필드, 스트리밍 응답 chunks, 픽션/내러티브 프롬프트 텍스트)이 포함되어 있습니다. 해당 위치의 모든 발견은 스위트를 실패시킵니다.

테스트 및 벤치마킹

세 계층 — 하나만으로는 스캐너의 주장을 신뢰하기에 충분하지 않기 때문입니다 — 정밀도와 재현율은 서로 다른 실패 모드이며, 둘 다 확인됩니다.

1. 픽스처 코퍼스 — 정밀도 + 재현율, 모든 빌드에서 실행됩니다.```bash npm test

[`test-fixtures/vulnerable/`](https://github.com/akanthed/secureai-scan/blob/main/test-fixtures/vulnerable) 및 [`test-fixtures/safe/`](https://github.com/akanthed/secureai-scan/blob/main/test-fixtures/safe)는 함께 스캔됩니다. 모든 취약한 픽스처는 `proven`/`likely` 증거(재현율)에서 예상 규칙을 발생시켜야 하며, 모든 안전한 픽스처는 **0건**의 `proven`/`likely` 결과(정밀도)를 생성해야 합니다. 빠르고 결정적이지만, 이는 스캐너가 테스트를 위해 특별히 작성된 코드에서만 올바르게 동작함을 입증할 뿐입니다.

**2. 실제 세계 회귀 벤치마크 — 우리가 작성하지 않은 공개 저장소를 대상으로.**```bash
npm run regression                          # scan the full curated repo set
npm run regression -- --fresh               # re-clone everything first
npm run regression -- openai-node           # scan just one repo by name
npm run regression -- --update-baseline     # accept the current findings

scripts/regression-scan.js는 큐레이션된 다양한 실제 공개 저장소(OpenAI/Anthropic/Vercel AI SDK, 공식 MCP 서버 및 TypeScript SDK, LlamaIndex, 그리고 스킬 번들 커버리지를 위한 anthropics/skillscisco-ai-defense/skill-scanner — TS와 Python, SDK 소비자 예제 코드와 SDK 작성자 소스를 아우름)를 복제하고, 각각을 빌드된 CLI로 스캔합니다.

test/regression-baseline.json에 이미 없는 proven/likely 발견 사항이 있으면 0이 아닌 종료 코드로 종료합니다 — 이 파일은 소스 라인과 대조하여 이미 검토된 발견 사항의 수작업 검토 기록입니다. 지문은 repo|rule|file이며 줄 번호가 아니므로, 일반적인 업스트림 변경으로 인한 노이즈가 발생하지 않습니다. 새 지문은 스캐너가 정당화해야 하는 주장입니다: 실제 문제가 아니라면 규칙 버그이며, 근본 원인에서 수정되고 test-fixtures/safe/ 픽스처로 고정됩니다. 읽지 않은 발견 사항을 베이스라인에 추가하는 것은 메커니즘 전체를 무력화합니다.

스킬 번들 커버리지는 별도로 다룹니다cisco-ai-defense/skill-scannerevals/ 코퍼스에는 레이블이 지정되어 있기 때문입니다. 20개의 픽스처 각각은 _expected.json 판정을 제공하며 문자 그대로 malicious/ 또는 safe/라는 디렉터리 아래에 있으므로, 정밀도 확인뿐 아니라 재현율 확인 역할도 합니다: 범위 내 악성 픽스처 6/6이 탐지되고, safe로 레이블된 항목에서는 0건의 발견 사항이 있으며, anthropics/skills의 실제 번들 18개 전체와 vercel/ai의 14개 전체에서도 0건의 발견 사항이 있습니다. (나머지 Cisco 범주 — SQL 삽입, 경로 탐색, 리소스 고갈, 함수 인자의 일반적인 eval(), 네 개 파일에 걸쳐 의도적으로 분할된 페이로드 — 는 문서화된 LLM/MCP/RAG 범위를 벗어나거나 단일 파일 내 결합 분석을 넘어섭니다. 각각에 대한 구체적인 근거는 0.6.0 변경 로그 항목을 참조하세요.)

원래 정밀도 수정을 주도한 실행의 과거 전/후 비교(기본 증거 수준의 발견 사항, --paranoid 없음):

저장소이전이후무엇이 잘못되었나
vercel/ai7731examples/, 최상위 tests/, 하이픈으로 연결된 ecosystem-tests/ 스타일 디렉터리가 낮은 신뢰 경로로 인식되지 않았음; chunks(일반적인 스트리밍 응답 변수)가 명확한 RAG 증거로 처리됨
openai/openai-node470동일한 경로 감지 격차가 SDK 자체의 examples//ecosystem-tests/에 적용됨
anthropics/anthropic-sdk-typescript20최상위 tests/ 디렉터리의 동일한 경로 감지 격차
modelcontextprotocol/typescript-sdk30token_endpoint/tokenType 스타일 OAuth 메타데이터 필드가 유출된 비밀로 플래그됨
run-llama/llama_index1815Python 검사가 "system prompt"를 포함한 모든 description= 필드를 컨텍스트와 무관하게 proven MCP 도구 중독으로 플래그함. 나머지 15개는 라이브러리 자체의 일반 검색기 정의에 대한 VEC001 적중 — 벡터 DB SDK의 자체 소스를 스캔하는 것이므로 확인할 필터가 존재할 수 없음. 정직하고 본질적인 한계이며 버그가 아님

현재 실행 (2026-08-06) — 버전별 증거는 docs/benchmarks/v0.9.0.json에 기록됨:

저장소발견 사항규칙상태
openai-node, anthropic-sdk-typescript, anthropic-sdk-python, modelcontextprotocol/typescript-sdk, modelcontextprotocol/servers0깨끗함
anthropics/skills (실제 스킬 번들 18개)0깨끗함 — SKL001–005에 대한 순수 정밀도 확인
vercel/ai (파일 5,691개)0트리아지 전에는 40건(AI001, AI003, AI005, AI010, MCP002)이었음 — 모든 항목을 소스와 대조하여 수작업 검토했고 모두 오탐으로 확인되었으며, 3개의 독립적인 근본 원인 버그(아래 참조)로 추적되어 수정되었고, 전체 재스캔에서 다시 깨끗함이 확인됨
run-llama/llama_index46VEC001본질적 한계, 버그 아님 — 테넌트 필터가 존재할 수 없는 라이브러리 자체의 일반 검색기 정의
cisco-ai-defense/skill-scanner7SKL001, SKL002, SKL005모두 malicious/로 레이블된 픽스처에 있음 — 범위 내 6/6, safe/로 레이블된 항목에서는 0건

vercel/ai 트리아지는 세 가지 실제 근본 원인 버그를 발견했습니다 — v0.6.0 스킬 규칙에 특화된 것은 없으며, 모두 여러 규칙에서 사용되는 공유 로직에 있었습니다:

  1. resolveLlmSink가 메서드 이름과 무관하게 LLM SDK 모듈로 해석된 모든 호출을 모델 호출로 처리함generateText와 함께 ai 패키지가 내보내는 타입 가드인 isToolUIPart를 LLM 호출로 플래그함. 이것만으로 5개 발견 그룹 중 3개(AI001, AI003, AI010)가 발생했습니다.
  2. AI005의 DANGEROUS_CALLEES에 SQL 삽입 스타일 싱크용 "query"가 포함되어 있지만, "query"는 합법적인 LLM/에이전트 호출 동사이기도 함 — Claude Agent SDK 자체 모델 호출인 claudeSdk.query({ prompt, options })가 공유 메서드 이름만으로 "위험한 싱크로 전달된 LLM 출력"으로 플래그되었습니다.
  3. REQUEST_SOURCES(MCP002, MCP010, VEC003에 걸쳐 동일하게 중복됨)가 단순한 "params."와 일치함 — 반드시 HTTP 요청 데이터가 아닌, 관례적으로 params라는 이름의 모든 함수 매개변수. URL 스킴 검증기(assertOpenLinkParams(params: unknown))가 "사용자 입력의 MCP 서버 URL"로 플래그되었습니다.

세 가지 모두 근본 원인(특정 호출 사이트가 아님)에서 수정되었고 test-fixtures/ 아래 영구 픽스처로 고정되었습니다. 전체 세부 사항은 CHANGELOG.md에 있습니다.

3. 취약-대-패치 검증 — 정밀도가 아닌 재현율을 증명합니다.

위의 두 계층은 스캐너가 안전한 코드에서 조용히 유지되는지만 확인합니다. DEP003의 권고 검사는 반대 방향으로 검증됩니다: 문서화된 취약 버전에 패키지를 고정하고 플래그되는지 확인한 다음, 패치된 버전에 고정하고 플래그되지 않는지 확인합니다.```bash node --test test/dependency-guard.test.js

covers: `[email protected]` (CVE-2025-6514, 취약) 플래그됨 / `[email protected]` (패치됨) 통과; `[email protected]` (백도어 이전) 통과 / `[email protected]` (이후 — 악성 패키지에는 합법적인 패치가 존재하지 않음) 여전히 플래그됨; `llama-cpp-python==0.2.71` (CVE-2024-34359, OSV 생성 세트에서) 플래그됨 / `==0.2.72` (패치됨) 통과, PyPI 이름 정규화(`llama_cpp_python`) 하에서도 포함; 그리고 `langchain>=0.1.0` 스타일의 고정되지 않은 지정자는 기본 보고에서 **0건**의 결과를 생성함. 이 테스트를 구축하면서 실제 격차를 발견했습니다: `DEP003`은 패키지 이름으로만 권고를 매칭했고, 선언된 버전을 권고의 영향 범위와 실제로 비교하지 않았습니다 — [`src/scanner/semver.ts`](https://github.com/akanthed/secureai-scan/blob/main/src/scanner/semver.ts)에서 수정됨.

모호성은 권고 종류별로 의도적으로 다르게 해결됩니다. **악성** 패키지는 선언된 버전을 확인할 수 없어도 플래그가 발생합니다 — 백도어 설치를 되돌릴 수 없으므로 플래그 쪽으로 실패합니다. **CVE**는 선언된 버전이 영향 범위 내에 있음이 입증 가능한 정확한 고정 버전일 때만 `proven`으로 발생합니다. 고정되지 않았지만 영향을 받을 가능성이 있는 경우 `heuristic`(`--paranoid` 전용)으로 내려갑니다. 악성 종류 규칙을 162개 항목의 CVE 스냅샷에 적용하면 `langchain>=0.1.0`을 선언하는 모든 저장소에 치명적 결과가 발생합니다 — 규모에 따라 실행 불가능한 노이즈입니다.

## 로드맵

출시된 기능과 계획된 기능은 [`ROADMAP.md`](https://github.com/akanthed/secureai-scan/blob/main/ROADMAP.md)를 참조하세요. 두 언어 엔진 모두 AST 기반입니다: TypeScript/JavaScript용 ts-morph와 Python용 Tree-sitter. Python의 import, 호출, 할당, 데코레이터, 스코프, 키워드 인자, 딕셔너리 필드, 문자열은 모두 구문 노드입니다. 대상 코드는 절대 import되거나 실행되지 않으며, Python 인터프리터도 필요하지 않습니다. 남은 Python 격차는 함수/파일 간 오염 깊이로 제한되며, 파싱 문제가 아닙니다. 스캔 성능과 알려진 제한 사항은 [`docs/Performance.md`](https://github.com/akanthed/secureai-scan/blob/main/docs/Performance.md)에 문서화되어 있습니다.

## 기여

기여를 환영합니다 — 워크플로는 [`CONTRIBUTING.md`](https://github.com/akanthed/secureai-scan/blob/main/CONTRIBUTING.md)를, 위의 정밀도 기준을 충족하는 탐지 규칙을 추가하는 방법은 [`docs/WritingRules.md`](https://github.com/akanthed/secureai-scan/blob/main/docs/WritingRules.md) / [`docs/RuleDevelopment.md`](https://github.com/akanthed/secureai-scan/blob/main/docs/RuleDevelopment.md)를 참조하세요. 모든 새 규칙에는 [`test-fixtures/vulnerable/`](https://github.com/akanthed/secureai-scan/blob/main/test-fixtures/vulnerable)과 [`test-fixtures/safe/`](https://github.com/akanthed/secureai-scan/blob/main/test-fixtures/safe) 양쪽에 픽스처, `src/scanner/catalog.ts`의 항목, `test/corpus.test.js`의 테스트 케이스가 필요합니다 — `npm test`가 세 가지를 모두 강제합니다.

## 라이선스

MIT © Akshay Kanthed

카테고리