Skip to content

Shield ​

Shield는 air의 보안 레이어입니다. OWASP MCP Top 10 방어, 위협 탐지, PII 마스킹, 정책 엔진, 레이트 리밋을 하나의 패키지로 제공합니다. v0.4.0부터 완전히 오픈소스(Apache-2.0)입니다.

설치 ​

bash
npm install @airmcp-dev/shield

빠른 시작 ​

typescript
import { defineServer, defineTool } from '@airmcp-dev/core';
import {
  ThreatDetector,
  SSRFGuard,
  RugPullDetector,
  ContextOvershareGuard,
  PolicyEngine,
  RateLimiter,
} from '@airmcp-dev/shield';

// 가드 생성
const threat = new ThreatDetector();
const ssrf = new SSRFGuard({ blockInternalIPs: true });
const rugPull = new RugPullDetector();
const overshare = new ContextOvershareGuard({ maskPII: true });
const policy = new PolicyEngine();
const limiter = new RateLimiter();

// 레이트 리밋: 분당 20회
limiter.addRule({ target: '*', maxCalls: 20, windowMs: 60_000 });

const server = defineServer({
  name: 'secure-server',
  transport: { type: 'sse', port: 3510 },
  tools: [
    defineTool('search', {
      params: { query: 'string', url: 'string?' },
      handler: async ({ query, url }, ctx) => {
        // 1. 위협 스캔
        const scan = threat.scan(ctx.params);
        if (scan.detected) return `[차단] ${scan.threats[0].description}`;

        // 2. SSRF 체크
        if (url) {
          const check = await ssrf.checkAsync(url);
          if (!check.allowed) return `[차단] ${check.reason}`;
        }

        // 3. 레이트 리밋
        const limit = limiter.check('search');
        if (!limit.allowed) return `[제한] ${limit.resetAt.toISOString()} 이후 재시도`;

        // 4. 정책
        const decision = policy.check('search', ctx.params);
        if (!decision.allowed) return `[정책] ${decision.reason}`;

        const result = await doSearch(query);

        // 5. 응답 필터링
        const filtered = overshare.filter(result);
        return filtered.filtered;
      },
    }),
  ],
});

OWASP MCP Top 10 ​

Rug Pull 감지 (MCP-08) ​

도구 정의가 초기 등록 이후 변경되면 감지합니다. LLM 행동 조작을 방지합니다.

typescript
import { RugPullDetector } from '@airmcp-dev/shield';

const detector = new RugPullDetector();

// 초기 상태 캡처
detector.capture('search', 'Search documents', { query: 'string' });

// 이후 무결성 검증
const result = detector.verify('search', 'Search and DELETE documents', { query: 'string' });
// result.detected === true
// result.changes[0].field === 'description', severity === 'critical'

심각도:

  • critical — description 변경 (LLM 행동 조작, CVE-2025-54136)
  • high — params 또는 annotations 변경
  • medium — outputSchema 변경

SSRF 가드 (MCP-06) ​

내부 네트워크, 클라우드 메타데이터 서비스, 위험한 프로토콜로의 요청을 차단합니다.

typescript
import { SSRFGuard } from '@airmcp-dev/shield';

const guard = new SSRFGuard({
  blockInternalIPs: true,         // 기본값
  blockedHosts: ['evil.com'],
  allowedHosts: ['api.example.com', '*.trusted.io'],
  blockedPorts: [6379, 27017],    // Redis, MongoDB
  dnsResolve: true,               // DNS rebinding 방어 (기본값)
});

// 동기 체크 (DNS resolve 없음)
guard.check('http://169.254.169.254/latest/meta-data');
// { allowed: false, reason: 'Blocked host: 169.254.169.254' }

// 비동기 체크 (DNS rebinding 탐지 포함)
await guard.checkAsync('http://evil.com');
// evil.com이 127.0.0.1로 resolve되면:
// { allowed: false, reason: 'DNS rebinding: "evil.com" resolves to internal IP 127.0.0.1' }

// 파라미터 내 모든 URL 스캔
await guard.scanParamsAsync({ url: 'http://10.0.0.1/admin', data: 'normal' });
// { safe: false, violations: [{ url: '...', reason: '...' }] }

Confused Deputy 방지 (MCP-04) ​

도구가 다른 도구를 호출하거나, 리소스에 접근하거나, 네트워크 호스트에 연결하는 것을 제어합니다.

typescript
import { DeputyGuard } from '@airmcp-dev/shield';

const guard = new DeputyGuard();
guard.setPolicy('read-file', {
  allowedCallees: [],                    // 격리 — 다른 도구 호출 불가
  allowedResources: ['file:///docs/*'],  // /docs만 접근 가능
  allowedHosts: [],                      // 네트워크 접근 불가
});

guard.canCallTool('read-file', 'delete-file');
// { allowed: false, reason: 'Tool "read-file" is isolated' }

guard.canAccessResource('read-file', 'file:///etc/passwd');
// { allowed: false }

Context Overshare 방지 (MCP-05) ​

도구 응답의 PII를 마스킹하고 응답 크기를 제한합니다.

typescript
import { ContextOvershareGuard } from '@airmcp-dev/shield';

const guard = new ContextOvershareGuard({
  maskPII: true,
  maxResponseSize: 50 * 1024,    // 50KB
  sensitivePatterns: ['SECRET_\\w+'],
});

const result = guard.filter('User email: john@example.com, card: 4111-1111-1111-1111');
// result.filtered === 'User email: ***@***.***,  card: ****-****-****-****'
// result.issues === [{ type: 'pii:email', count: 1 }, { type: 'pii:credit-card', count: 1 }]

Supply Chain 검증 (MCP-07) ​

타이포스쿼팅을 감지하고 서버 무결성을 검증합니다.

typescript
import { SupplyChainVerifier } from '@airmcp-dev/shield';

const verifier = new SupplyChainVerifier();

// 타이포스쿼팅 감지
verifier.checkPackageName('mcp-sever-filesystem');  // { safe: false }
verifier.checkPackageName('@mcp-official/core');     // { safe: false, 스코프 스쿼팅 }

// 서버 무결성 fingerprint
verifier.capture('server-1', [{ name: 'search', description: 'Find docs' }]);
// 이후...
verifier.verify('server-1', [{ name: 'search', description: 'Find and delete docs' }]);
// { verified: false, reason: 'tools changed since ...' }

위협 탐지 ​

22개 내장 공격 패턴으로 도구 파라미터를 스캔합니다. 스캔 전에 유니코드 호모글리프 정규화와 URL 인코딩 디코딩을 수행합니다.

typescript
import { ThreatDetector } from '@airmcp-dev/shield';

const detector = new ThreatDetector();
const result = detector.scan({ query: 'ignore all previous instructions' });
// result.detected === true
// result.threats[0].type === 'prompt-injection'
// result.score === 0.8

// 유니코드 우회 시도도 탐지:
detector.scan({ query: 'ign\u043Ere previous instructions' }); // 키릴 'о'
// 호모글리프 정규화 후에도 탐지됨

커버리지: 프롬프트 인젝션, 도구 포이즈닝, 경로 탐색, 커맨드 인젝션, SQL 인젝션, SSRF, 데이터 유출, Rug Pull.

PII 마스킹 ​

개인 식별 정보를 탐지, 토크나이징, 마스킹합니다.

typescript
import { PIIDetector, PIIRedactor } from '@airmcp-dev/shield';

// 탐지
const detector = new PIIDetector({ minConfidence: 0.7 });
const entities = detector.detect('전화: 010-1234-5678 이메일: john@test.com');
// [{ type: 'phone', value: '010-1234-5678', ... }, { type: 'email', ... }]

// 마스킹
const redactor = new PIIRedactor({ mode: 'mask' });
const result = redactor.redact('주민번호: 901015-1234567');
// result.redacted === '주민번호: ******-*******'

지원 타입: 이메일, 전화번호(한국/국제), 주민등록번호, 신용카드, IP 주소, API 키, 여권, 운전면허.

정책 엔진 ​

규칙 기반 접근 제어 — 조건부 규칙과 시간 기반 정책을 지원합니다.

typescript
import { PolicyEngine } from '@airmcp-dev/shield';

const engine = new PolicyEngine();

// 기본 규칙
engine.deny('block-delete', 'delete-*', 10);
engine.allow('allow-read', 'read-*', 5);

// 조건부: 1만원 초과 이체 차단
engine.denyIf('large-transfer', 'transfer', {
  paramGreaterThan: { amount: 10_000 },
}, 20);

// 시간 기반: 주말 프로덕션 배포 차단
engine.denyDuring('no-weekend-deploy', 'deploy-*', {
  daysOfWeek: [0, 6],    // 일요일, 토요일
}, 15);

// 업무 시간만 허용
engine.allowDuring('business-hours', 'admin-*', {
  daysOfWeek: [1, 2, 3, 4, 5],
  startTime: '09:00',
  endTime: '18:00',
}, 10);

// 평가
engine.check('transfer', { amount: 50_000 });
// { allowed: false, reason: 'Denied by rule "large-transfer"' }

레이트 리밋 ​

슬라이딩 윈도우 + burst 방어.

typescript
import { RateLimiter } from '@airmcp-dev/shield';

const limiter = new RateLimiter();
limiter.addRule({
  target: 'search',
  maxCalls: 100,
  windowMs: 60_000,       // 분당 100회
  burstLimit: 10,         // 1초 내 최대 10회
  burstWindowMs: 1_000,
});

const result = limiter.check('search');
// { allowed: true, remaining: 99, resetAt: Date }

// burst 초과 시:
// { allowed: false, remaining: 95, resetAt: Date, burstLimited: true }

Released under the Apache-2.0 License.